<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-833174317742362874</id><updated>2012-01-31T02:49:08.094-08:00</updated><category term='strlcpy'/><category term='Portability'/><category term='flash'/><category term='Dolphin'/><category term='lighttpd'/><category term='File Dialog'/><category term='file descriptor'/><category term='bugs'/><category term='fgets'/><category term='competition'/><category term='Windows'/><category term='open source'/><category term='binary'/><category term='variadic templates'/><category term='HTTP'/><category term='FatELF'/><category term='GCC'/><category term='PHB'/><category term='iphone'/><category term='searching'/><category term='Mac OS X'/><category term='PC'/><category term='lambda functions'/><category term='C++ 2011'/><category term='insane ideas'/><category term='BIOS'/><category term='torture'/><category term='SSH'/><category term='standards compliance'/><category term='readdir'/><category term='parameters'/><category term='language'/><category term='Hashing'/><category term='fstatat'/><category term='school'/><category term='Blogger'/><category term='coreutils'/><category term='opendir'/><category term='__func__'/><category term='Antisemitism'/><category term='fcntl'/><category term='compatibility'/><category term='Firefox'/><category term='getcwd'/><category term='MSVC'/><category term='Qt'/><category term='buffer overflow'/><category term='c99'/><category term='factory'/><category term='tree'/><category term='Optimization'/><category term='recursion'/><category term='x86-64'/><category term='unsigned'/><category term='stat'/><category term='Function Pointers'/><category term='pure failure'/><category term='secure'/><category term='Cfront'/><category term='modconf'/><category term='directory'/><category term='good code'/><category term='x86'/><category term='gnu'/><category term='protocols'/><category term='ManyMouse'/><category term='export'/><category term='BSD'/><category term='closed source'/><category term='OSS'/><category term='GNOME'/><category term='types'/><category term='C++-0x'/><category term='GUI'/><category term='GTK'/><category term='realpath'/><category term='Mozilla'/><category term='Trolltech'/><category term='Ancient Coding Ideas'/><category term='debian'/><category term='strlmrg'/><category term='CPU Detection'/><category term='linux'/><category term='apache'/><category term='bad code'/><category term='KDE'/><category term='non rectangular array'/><category term='PATH_MAX'/><category term='quicksort'/><category term='signed'/><category term='fchmod'/><category term='C++-201x'/><category term='gzdirect'/><category term='openat'/><category term='Library'/><category term='sorting'/><category term='ftruncate'/><category term='files'/><category term='multicore'/><category term='discrimination'/><category term='gets'/><category term='strlcat'/><category term='API'/><category term='Google'/><category term='tar'/><category term='ALSA'/><category term='crazy executives'/><category term='Political Correctness'/><category term='initializer lists'/><category term='multiseat'/><category term='code search'/><category term='save_cwd'/><category term='gzdopen'/><category term='Television'/><category term='distribution'/><title type='text'>Insane Coding</title><subtitle type='html'>'coz good thinking requires going outside the box</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://insanecoding.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/833174317742362874/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://insanecoding.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>insane coder</name><uri>http://www.blogger.com/profile/06901386115570670209</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>57</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-833174317742362874.post-5732990615606983833</id><published>2011-12-14T07:58:00.000-08:00</published><updated>2011-12-14T14:01:25.135-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='GTK'/><category scheme='http://www.blogger.com/atom/ns#' term='File Dialog'/><category scheme='http://www.blogger.com/atom/ns#' term='crazy executives'/><category scheme='http://www.blogger.com/atom/ns#' term='GNOME'/><category scheme='http://www.blogger.com/atom/ns#' term='Mozilla'/><category scheme='http://www.blogger.com/atom/ns#' term='Political Correctness'/><category scheme='http://www.blogger.com/atom/ns#' term='debian'/><category scheme='http://www.blogger.com/atom/ns#' term='Windows'/><category scheme='http://www.blogger.com/atom/ns#' term='distribution'/><category scheme='http://www.blogger.com/atom/ns#' term='Firefox'/><category scheme='http://www.blogger.com/atom/ns#' term='competition'/><category scheme='http://www.blogger.com/atom/ns#' term='KDE'/><category scheme='http://www.blogger.com/atom/ns#' term='pure failure'/><category scheme='http://www.blogger.com/atom/ns#' term='compatibility'/><category scheme='http://www.blogger.com/atom/ns#' term='torture'/><category scheme='http://www.blogger.com/atom/ns#' term='Mac OS X'/><title type='text'>Progression and Regression of Desktop User Interfaces</title><content type='html'>As this Gregorian year comes to a close, with various new interfaces out now, and some new ones on the horizon, I decided to recap my personal experiences with user interfaces on the desktop, and see what the future will bring.&lt;br /&gt;&lt;br /&gt;When I was younger, there were a few desktop environments floating around, and I've seen a couple of them at school or a friend's house. But the first one I had on my own personal computer, and really played around with was Windows 3.&lt;br /&gt;&lt;br /&gt;Windows 3 came with something called Program Manager. Here's what it looked like:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/-LGd15rvRKqA/TujJXGRNAKI/AAAAAAAAAHk/c26JCwBHpDk/s1600/Program_Manager.png"&gt;&lt;img style="display: block; margin: 0px auto 10px; text-align: center; cursor: pointer; width: 320px; height: 210px;" src="http://4.bp.blogspot.com/-LGd15rvRKqA/TujJXGRNAKI/AAAAAAAAAHk/c26JCwBHpDk/s320/Program_Manager.png" alt="" id="BLOGGER_PHOTO_ID_5686015928212193442" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/-F9Y_kTh71Bw/TujJXdQsy0I/AAAAAAAAAHs/Z3yG7hGFsb8/s1600/program-manager-internet-explorer.png"&gt;&lt;img style="display: block; margin: 0px auto 10px; text-align: center; cursor: pointer; width: 320px; height: 240px;" src="http://4.bp.blogspot.com/-F9Y_kTh71Bw/TujJXdQsy0I/AAAAAAAAAHs/Z3yG7hGFsb8/s320/program-manager-internet-explorer.png" alt="" id="BLOGGER_PHOTO_ID_5686015934384098114" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;The basic idea was that you had a "start screen", where you had your various applications grouped by their general category. Within each of these "groups", you had shortcuts to the specific applications. Now certain apps like a calculator you only used in a small window, but most serious apps were only used maximized. If you wanted to switch to another running app, you either pressed the alt+tab keyboard shortcut to cycle through them, or you minimized everything, where you then saw a screen listing all the currently running applications.&lt;br /&gt;&lt;br /&gt;Microsoft also shipped a very nice file manager, known as "File Manager", which alone made it useful to use Windows. It was rather primitive though, and various companies released various add-ons for it to greatly enhance its abilities. I particularly loved Wiz File Manager Pro.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/-f3kvvBB5TGI/TujmZowSikI/AAAAAAAAAH8/0nTN6sTK34c/s1600/fileman.png"&gt;&lt;img style="display: block; margin: 0px auto 10px; text-align: center; cursor: pointer; width: 320px; height: 240px;" src="http://3.bp.blogspot.com/-f3kvvBB5TGI/TujmZowSikI/AAAAAAAAAH8/0nTN6sTK34c/s320/fileman.png" alt="" id="BLOGGER_PHOTO_ID_5686047857666329154" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Various companies also made add-ons for Program Manager, such as to allow nested groups, or shortcuts directly on the main screen outside of a group, or the ability to change the icons of selected groups. Microsoft would've probably built some of these add-ons in if it continued development of Program Manager.&lt;br /&gt;&lt;br /&gt;Now not everyone used Windows all the time back then, but only selectively started it up when they wanted something from it. I personally did everything in DOS unless I wanted to use a particular Windows app, such as file management or painting, or copying and pasting stuff around. Using Windows all the time could be annoying as it slowed down some DOS apps, or made some of them not start at all due to lack of memory and other issues.&lt;br /&gt;&lt;br /&gt;In the summer of 1995, Microsoft released Windows 4 to the world. It came bundled with MS-DOS 7, and provided a whole new user experience.&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/-VDrDcboMELI/Tujo1PoXc-I/AAAAAAAAAII/BEtbuoVwtcg/s1600/windows95.png"&gt;&lt;img style="display: block; margin: 0px auto 10px; text-align: center; cursor: pointer; width: 320px; height: 240px;" src="http://2.bp.blogspot.com/-VDrDcboMELI/Tujo1PoXc-I/AAAAAAAAAII/BEtbuoVwtcg/s320/windows95.png" alt="" id="BLOGGER_PHOTO_ID_5686050530981802978" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Now the back-most window, the "desktop", no longer contained a list of the running programs (in explorer.exe mode), but rather you could put your own shortcuts and groups and groups of groups there. Rather running programs would appear at the bottom of the screen in a "taskbar". The taskbar now also contained a clock, and a "start menu", to launch applications. Some always running applications which were meant to be background tasks appeared as a tiny icon next to the clock in an area known as a "tray".&lt;br /&gt;&lt;br /&gt;This was a major step forward in usability. Now, no matter which application you were currently using, you could see all the ones that were currently running on the edge of your screen. You could also easily click on one of them to switch to it. You didn't need to minimize all to see them anymore. Thanks to the start menu, you could also easily launch all your existing programs without needing to minimize all back down to Program Manager. The clock always being visible was also a nice touch.&lt;br /&gt;&lt;br /&gt;Now when this came out, I could appreciate these improvements, but at the same time, I also hated it. A lot of us were using 640x480 resolutions on 14" screens back then. Having something steal screen space was extremely annoying. Also with how little memory systems had back at the time (4 or 8 MB of RAM), you generally weren't running more than 2 or 3 applications at a time and could not really appreciate the benefits of having an always present taskbar. Some people played with taskbar auto-hide because of this.&lt;br /&gt;&lt;br /&gt;The start menu was also a tad ridiculous. Lots of clicks were needed to get anywhere. The default appearance also had too many useless things on it.&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/-qMXIhbbGRWM/TujrotSaWaI/AAAAAAAAAIU/BPeKanOiPag/s1600/startmenu.png"&gt;&lt;img style="display: block; margin: 0px auto 10px; text-align: center; cursor: pointer; width: 320px; height: 320px;" src="http://3.bp.blogspot.com/-qMXIhbbGRWM/TujrotSaWaI/AAAAAAAAAIU/BPeKanOiPag/s320/startmenu.png" alt="" id="BLOGGER_PHOTO_ID_5686053614139365794" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;Did anyone actually use help? Did most people launch things from documents? Microsoft released a nice collection of utilities called "PowerToys" which contained "TweakUI" which you could use to make things work closer to how you want.&lt;br /&gt;&lt;br /&gt;The default group programs installed to within the start menu was quite messy though. Software installers would not organize their shortcuts into the groups that Windows came with, but each installed their apps into their own unique group. Having 50 submenus pop out was rather unwieldy, and I personally organized each app after I installed it. Grouping into "System Tools", "Games", "Internet Related Applications", and so on. It was annoying to manually do all this though, as when removing an app, you had to remove its group manually. On upgrades, one would also have to readjust things each time too.&lt;br /&gt;&lt;br /&gt;Windows 4 also came with the well known Windows Explorer file manager to replace the older one. It was across the board better than the vanilla version of File Manager that shipped with Windows 3.&lt;br /&gt;&lt;br /&gt;I personally started dual booting MS-DOS 6.22 + Windows for Workgroups 3.11 and Windows 95 (and later tri-booted with OS/2 Warp). Basically I used DOS and Windows for pretty much everything, and Windows 95 for those apps that required it. Although I managed to get most apps to work with Windows 3 using Win32s.&lt;br /&gt;&lt;br /&gt;As I got a larger screen and more RAM though, I finally started to appreciate what Windows 4 offered, and started to use it almost exclusively. I still exited Windows into DOS 7 though for games that needed to use more RAM, or ran quicker that way on our dinky processors from back then.&lt;br /&gt;&lt;br /&gt;Then Windows 4.10 / Internet Explorer 4 came out which offered a couple of improvements. First was "quick launch" which allowed you to put shortcuts directly on your taskbar. You could also make more than one taskbar and put all your shortcuts on it. I personally loved this feature, I put one taskbar on top of my screen, and loaded it with shortcuts to all my common applications, and had one on the bottom for classical use. Now I only had to dive into the start menu for applications I rarely used.&lt;br /&gt;&lt;br /&gt;It also offered a feature called "active desktop" which made the background of the desktop not just an image, but a web page. I initially loved the feature, as I edited my own page, and stuck in an input line which I would use to launch a web browser to my favorite search engine at the time (which changed monthly) with my text already searched for. After a while active desktop got annoying though, as every time IE crashed, it disabled it, and you had to deal with extra error messages, and go turn it on manually.&lt;br /&gt;&lt;br /&gt;By default this new version also made every Windows Explorer window have this huge sidebar stealing your precious screen space. Thankfully though, you could turn it off.&lt;br /&gt;&lt;br /&gt;All in all though, as our CPUs got faster, RAM became cheaper, and large screens more available, this interface was simply fantastic. I stopped booting into other OSs, or exiting Windows itself.&lt;br /&gt;&lt;br /&gt;Then Windows 5 came out for consumers, and UI wise, there weren't really any significant changes. The default look used these oversized bars and buttons on each window, but one could easily turn that off. The start menu got a bit of a rearrangement to now feature your most used programs up front, and various actions got pushed off to the side. Since I already put my most used programs on my quick launch on top, this start menu was a complete waste of space. Thankfully, it could also be turned off. I still kept using Windows 98 though, as I didn't see any need for this new Windows XP, and it was just a memory hog in comparison at the time.&lt;br /&gt;&lt;br /&gt;What was more interesting to me however was that at work, all our machines ran Linux with GNOME and KDE. When I first started working there, they made me take a course on how to use Emacs, as every programmer needs a text editor. I was greatly annoyed by the thing however, where was my shift highlight with shift+delete and shift+insert or ctrl+x and ctrl+v cut and paste? Thankfully though I soon found gedit and kedit which was like edit/notepad/wordpad but for Linux.&lt;br /&gt;&lt;br /&gt;Now I personally don't use a lot of windowsy type software often. My primary usage of a desktop consists of using a text editor, calculator, file manager, console/terminal/prompt, hex editor, paint, cd/dvd burner, and web browser. Only rarely do I launch anything else. Perhaps a PDF, CHM, or DJVU reader when I need to read something.&lt;br /&gt;&lt;br /&gt;After using Linux with GNOME/KDE at work for a while, I started to bring more of my work home with me and wanted these things installed on my own personal computer. So dual booting Windows 98 + Linux was the way to go. I started trying to tweak my desktop a bit, and found that KDE was way more capable than GNOME, as were most of their similar apps that I was using. KDE basically offered me everything that I loved about Windows 98, but on steroids. KWrite/KATE was notepad/wordpad but on steroids. The syntax highlighting was absolutely superb. KCalc was a fine calc.exe replacement. Konqueror made Windows Explorer seem like a joke in comparison.&lt;br /&gt;&lt;br /&gt;Konqueror offered network transparency, thumbnails of everything rather quickly, even of text files (no pesky thumbs.db either!). An info list view which was downright amazing:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/-IoKmHGtj0HE/Tuj4EwBsoeI/AAAAAAAAAIg/tFdhJ1qhkcM/s1600/konq.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 130px;" src="http://2.bp.blogspot.com/-IoKmHGtj0HE/Tuj4EwBsoeI/AAAAAAAAAIg/tFdhJ1qhkcM/s320/konq.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5686067290050437602" /&gt;&lt;/a&gt;This is a must have feature here. Too often are documents distributed under meaningless file names. With this, and many other small features, nothing else I've seen has even come close to Konqueror in terms of file management.&lt;br /&gt;&lt;br /&gt;Konsole was just like my handy DOS Prompt, except with tab support, and better maximizing, and copy and paste support. KHexEdit was simply better than anything I had for free on Windows. KolourPaint is mspaint.exe with support for way more image formats. K3b was also head and shoulders above Easy CD Creator or Nero Burning ROM. For Web Browsers, I was already using Mozilla anyway on Windows, and had the same option on Linux too.&lt;br /&gt;&lt;br /&gt;For the basic UI, not only did KDE have everything I liked about Windows, it came with an organized start menu. Which also popped out directly, instead from a "programs" submenu.&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/-5r8L9sci1ds/Tuj5oNzFjuI/AAAAAAAAAIs/ojcvSTR0NJY/s1600/kdestart.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 229px; height: 191px;" src="http://4.bp.blogspot.com/-5r8L9sci1ds/Tuj5oNzFjuI/AAAAAAAAAIs/ojcvSTR0NJY/s320/kdestart.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5686068998849269474" /&gt;&lt;/a&gt;&lt;br /&gt;The taskbar was also enhanced that I could stick various applets on it. I could stick volume control &lt;span style="font-weight:bold;"&gt;directly&lt;/span&gt; on it. Not a button which popped out a slider, the sliders themselves could appear on the taskbar. Now for example, I could easily adjust my microphone volume directly, without popping up or clicking on anything extra. There was an eyedropper which you could just push to find out the HTML color of anything appearing on the screen - great for web developers. Another thing which I absolutely love, I can see all my removable devices listed directly on my taskbar. If I have a disk in my drive, I see an icon for that drive appearing directly on my taskbar, and I can browse it, burn to it, eject it, whatever. With this, everything I need is basically at my finger tips.&lt;br /&gt;&lt;br /&gt;Before long I found myself using Linux/KDE all the time. On newer machines I started to dual boot Windows XP with Linux/KDE, so I could play the occasional Windows game when I wanted to, but for real work, I'd be using Linux.&lt;br /&gt;&lt;br /&gt;Then KDE 4 comes out, and basically half the stuff I loved about KDE was removed. No longer is it Windows on steroids. Now KDE 4.0 was not intended for public consumption. Somehow all the distros except for Debian seemed to miss that. Everyone wants to blame KDE for miscommunicating this, but it's quite clear 4.0 was only for developers if you watched the KDE 4 release videos. Any responsible package maintainer with a brain in their skull should've also realized that 4.0 was not ready for prime time. Yet it seems the people managing most distros are idiots that just need the "latest" version of everything, ignoring if it's better or not, or even stable.&lt;br /&gt;&lt;br /&gt;At the time, all these users were upset, and all started switching to GNOME. I don't know why anyone who truly loved the power KDE gave you would do that. If KDE 3 &gt; GNOME 2 &gt; KDE 4, why did people migrate to GNOME 2 when they could just not "upgrade" from KDE 3? It seems to me that people never really appreciated what KDE offers in the first place if they bothered moving to GNOME instead of keeping what was awesome.&lt;br /&gt;&lt;br /&gt;Nowadays people tell me that KDE 4 has feature parity with KDE 3, but I have no idea what they're talking about. The Konqueror info list feature that I described above still doesn't seem to exist in KDE 4. You can no longer have applets directly on your taskbar. Now I have to click a button to pop up a list of my devices, and only then can I do something with them. No way to quickly glance to see what is currently plugged in. Konsole's tabs now stretch to the full width of your screen for some pointless reason. If you want to switch between tabs with your mouse, prepare for carpal tunnel syndrome. Who thought that icons should grow if they can? It's exactly like those idiotic theoretical professors who spout that CPU usage must be maximized at all times, and therefore use algorithms that schedule things for maximum power draw, despite that in normal cases performance does not improve by using these algorithms. I'd rather pack in more data if possible, having multiple columns of information instead of just huge icons.&lt;br /&gt;&lt;br /&gt;KHexEdit has also been completely destroyed. No longer is the column count locked to hex (16). I can't imagine anyone who seriously uses a hex editor designed the new version. For some reason, KDE now also has to act like your mouse only has one button, and right click context menus vanished from all over the place. It's like the entire KDE development team got invaded by Mac and GNOME users who are too stupid to deal with anything other than a big button in the middle of the screen.&lt;br /&gt;&lt;br /&gt;Over in the Windows world. Windows 6 (with 6.1 comically being consumerized as "Windows 7") came out with a bit of a revamp. The new start menu seems to fail basic quality assurance tests for anything other than default settings. Try to set things to offer a classic start menu, this is what you get:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/-Mt2z6cUg-dQ/Tuj-8q2QzqI/AAAAAAAAAI4/IV8Nn-Le6PQ/s1600/windows7.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 267px; height: 320px;" src="http://1.bp.blogspot.com/-Mt2z6cUg-dQ/Tuj-8q2QzqI/AAAAAAAAAI4/IV8Nn-Le6PQ/s320/windows7.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5686074847802740386" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;If you use extra large icons for your grandparents, you also find that half of the Control Panel is now inaccessible. Ever since Bill Gates left, it seems Windows is going down the drain.&lt;br /&gt;&lt;br /&gt;But hardly are problems solely for KDE and Windows, GNOME 3 is also a major step back according to what most people tell me. Many of these users are now migrating to XFCE. If you like GNOME 2, why are you migrating to something else for? And what is it with people trying to fix what isn't broken? If you want to offer an alternate interface, great, but why break or remove the one you already have?&lt;br /&gt;&lt;br /&gt;Now a new version of Windows is coming out with a new interface being called "Metro". They should really be calling it "Retro". It's Windows 3 Program Manager with a bunch of those third party add-ons, with a more modern look to it. Gone is the Windows 4+ taskbar so you can see what was running, and easily switch applications via mouse. Now you'll need to press the equivalent of a minimize all to get to the actual desktop. Another type of minimize to get back to Program Manager to launch something else, or "start screen" as they're now calling it.&lt;br /&gt;&lt;br /&gt;So say goodbye to all the usability and productivity advantages Windows 4 offered us, they want to take us back to the "dark ages" of modern computing. Sure a taskbar-less interface makes sense on handheld devices with tiny screens or low resolution, but on modern 19"+ screens? The old Windows desktop+taskbar in the upcoming version of Windows is now just another app in their Metro UI. So "Metro" apps won't appear on the classic taskbar, and "classic" applications won't appear on the Metro desktop where running applications are listed.&lt;br /&gt;&lt;br /&gt;I'm amazed at how self destructive the entire market became over the last few years. I'm not even sure who to blame, but someone has to do something about it. It's nice to see that a small group of people took KDE 3.5, and are continuing to develop it, but they're rebranding everything with crosses everywhere and calling it "Trinity" desktop. Just what we need, to bring religious issues now into desktop environments. What next? The political desktop?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/833174317742362874-5732990615606983833?l=insanecoding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://insanecoding.blogspot.com/feeds/5732990615606983833/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=833174317742362874&amp;postID=5732990615606983833' title='16 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/833174317742362874/posts/default/5732990615606983833'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/833174317742362874/posts/default/5732990615606983833'/><link rel='alternate' type='text/html' href='http://insanecoding.blogspot.com/2011/12/progression-and-regression-of-desktop.html' title='Progression and Regression of Desktop User Interfaces'/><author><name>insane coder</name><uri>http://www.blogger.com/profile/06901386115570670209</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/-LGd15rvRKqA/TujJXGRNAKI/AAAAAAAAAHk/c26JCwBHpDk/s72-c/Program_Manager.png' height='72' width='72'/><thr:total>16</thr:total></entry><entry><id>tag:blogger.com,1999:blog-833174317742362874.post-1934168996693621718</id><published>2011-11-29T12:26:00.001-08:00</published><updated>2011-11-29T16:50:28.509-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='files'/><category scheme='http://www.blogger.com/atom/ns#' term='competition'/><category scheme='http://www.blogger.com/atom/ns#' term='API'/><category scheme='http://www.blogger.com/atom/ns#' term='GCC'/><category scheme='http://www.blogger.com/atom/ns#' term='Optimization'/><title type='text'>Reading in an entire file at once in C++, part 2</title><content type='html'>Last week I discussed &lt;a href="http://insanecoding.blogspot.com/2011/11/how-to-read-in-file-in-c.html"&gt;6 different methods on how to quickly get an entire file into a C++ string&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;The conclusion was that the straight forward method was the ideal method, this was verified across several compilers. Since then, people asked me a number of questions.&lt;br /&gt;&lt;br /&gt;What if I want to use a vector instead of a string, are the speeds different?&lt;br /&gt;Forget C++ containers, what about directly into a manually allocated buffer?&lt;br /&gt;What about copying into a buffer via mmap?&lt;br /&gt;What do these various cases say about compilers or their libraries? Can this indicate what they're good or bad at compiling?&lt;br /&gt;&lt;br /&gt;So to establish some baseline numbers, I created an application which reads the same files the same amount of times using the fastest method possible. It directly creates a buffer aligned to the partition's blocking factor, informs the OS to do the fastest possible sequential read, and then reads the file directly into the buffer. I also tested the suggested method to mmap a file, and copy the contents from there to an allocated buffer. The times achieved for these were 5 and 9 respectively. The latter is slower because of the extra memcpy() required, you want to read directly into your destination buffer whenever possible. The fastest time I now achieved should more or less be the fastest theoretical limit I'm able to get with my hardware. Both GCC and LLVM got the exact same times. I did not test with VC++ here as it doesn't support POSIX 2008.&lt;br /&gt;&lt;br /&gt;Now regarding our 6 methods from last time, all of them except the Rdbuf method are possible with std::vector, since there is no std::vector based std::istream.&lt;br /&gt;&lt;br /&gt;An interesting thing to note is that C++ string implementations vary greatly from implementation to implementation. Some offer optimizations for very small strings, some offer optimizations for frequent copies, by using reference counting. Some always ensure the string ends with a 0 byte so you can immediately pass them as a C string. In this latter case, operations which operate on strings as a range are rather quick, as the data is copied, then a 0 is appended. Whereas a loop which constantly pushes bytes on the back will have to needlessly set the extra trailing byte to 0 each time. Vector implementations on the other hand don't need to worry about a trailing 0 byte, and generally don't try to internally use all kinds of elaborate storage methods. So if std::vector works for you, you may want to use that.&lt;br /&gt;&lt;br /&gt;Let's review times for the 5 applicable methods with our various compilers.&lt;br /&gt;&lt;br /&gt;GCC 4.6 with a vector:&lt;br /&gt;&lt;table&gt;&lt;tr&gt;&lt;th&gt;Method&lt;/th&gt;&lt;th&gt;Duration&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;C&lt;/td&gt;&lt;td&gt;23.5&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;C++&lt;/td&gt;&lt;td&gt;22.8&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Iterator&lt;/td&gt;&lt;td&gt;73&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Assign&lt;/td&gt;&lt;td&gt;81.8&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Copy&lt;/td&gt;&lt;td&gt;68&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;Whereas with a string:&lt;br /&gt;&lt;table&gt;&lt;tr&gt;&lt;th&gt;Method&lt;/th&gt;&lt;th&gt;Duration&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;C&lt;/td&gt;&lt;td&gt;24.5&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;C++&lt;/td&gt;&lt;td&gt;24.5&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Iterator&lt;/td&gt;&lt;td&gt;64.5&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Assign&lt;/td&gt;&lt;td&gt;68&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Copy&lt;/td&gt;&lt;td&gt;63&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;We see that with a vector, the basic methods became a bit faster, but interestingly enough, the others got slower. However, which methods are superior to the others have remained the same.&lt;br /&gt;&lt;br /&gt;Now for LLVM 3 with a vector:&lt;br /&gt;&lt;table&gt;&lt;tr&gt;&lt;th&gt;Method&lt;/th&gt;&lt;th&gt;Duration&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;C&lt;/td&gt;&lt;td&gt;8&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;C++&lt;/td&gt;&lt;td&gt;8&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Iterator&lt;/td&gt;&lt;td&gt;860&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Assign&lt;/td&gt;&lt;td&gt;1328&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Copy&lt;/td&gt;&lt;td&gt;930&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;Versus for string:&lt;br /&gt;&lt;table&gt;&lt;tr&gt;&lt;th&gt;Method&lt;/th&gt;&lt;th&gt;Duration&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;C&lt;/td&gt;&lt;td&gt;7.5&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;C++&lt;/td&gt;&lt;td&gt;7.5&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Iterator&lt;/td&gt;&lt;td&gt;110&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Assign&lt;/td&gt;&lt;td&gt;102&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Copy&lt;/td&gt;&lt;td&gt;97&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;With LLVM, everything is slower with a vector, and for the more complex solutions, much much slower. There's two interesting things we can see about LLVM though. For more straight forward logic, their compiler's optimizations are extremely smart. The speeds approach the theoretical best. I did some profiling on GCC and LLVM, as they're using the same C and C++ libraries, and found that in the straight C/C++ methods for my test program, GCC made 300 memory allocations, but LLVM made only 200. LLVM apparently is smart enough to see inside the various allocations, skip the ones that aren't needed, and place the data directly into the output buffer. But for complex code, LLVM's optimizations aren't that great. In the case of vectors and iterators, downright awful. Someone should file some bug reports with them.&lt;br /&gt;&lt;br /&gt;Now for Visual C++ 2010 using vector:&lt;br /&gt;&lt;table&gt;&lt;tr&gt;&lt;th&gt;Method&lt;/th&gt;&lt;th&gt;Duration&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;C&lt;/td&gt;&lt;td&gt;17.8&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;C++&lt;/td&gt;&lt;td&gt;18.7&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Iterator&lt;/td&gt;&lt;td&gt;180.6&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Assign&lt;/td&gt;&lt;td&gt;159.5&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Copy&lt;/td&gt;&lt;td&gt;165.6&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;And string:&lt;br /&gt;&lt;table&gt;&lt;tr&gt;&lt;th&gt;Method&lt;/th&gt;&lt;th&gt;Duration&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;C&lt;/td&gt;&lt;td&gt;16.5&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;C++&lt;/td&gt;&lt;td&gt;20.4&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Iterator&lt;/td&gt;&lt;td&gt;224.4&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Assign&lt;/td&gt;&lt;td&gt;222.8&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Copy&lt;/td&gt;&lt;td&gt;320&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;We see here that the Copy method, which uses push_back() got a huge performance improvement. This seems to indicate that the STL implementation adds a 0 at the end of each operation, especially push_back(), instead of just when c_str() is called. Otherwise, string is faster.&lt;br /&gt;&lt;br /&gt;It's also sad to see that GCC while winning all the cases where iterators were involved, was significantly slower in all the straight forward cases. This seems to indicate that GCC has the smartest optimizations, but fails to optimize well when the logic is straightforward. Someone should look into that.&lt;br /&gt;&lt;br /&gt;It seems if you're trying to hold a collection of bytes, or whatever your wchar_t is, but don't care about the specialties of any particular container, as long as you don't push_back() a lot, string seems to be faster.&lt;br /&gt;&lt;br /&gt;Finally, here's a table of all the compilers and methods I tested ordered by speed:&lt;br /&gt;&lt;br /&gt;&lt;table&gt;&lt;br /&gt;&lt;tr&gt;&lt;th&gt;Method&lt;/th&gt;&lt;th&gt;Duration&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;POSIX&lt;/td&gt;&lt;td&gt;5&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;LLVM 3.0 s C/C++&lt;/td&gt;&lt;td&gt;7.5&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;LLVM 3.0 v C/C++&lt;/td&gt;&lt;td&gt;8&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;MMAP&lt;/td&gt;&lt;td&gt;9&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;VC 2010 s C&lt;/td&gt;&lt;td&gt;16.5&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;VC 2010 v C&lt;/td&gt;&lt;td&gt;17.8&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;VC 2005 s C&lt;/td&gt;&lt;td&gt;18.3&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;VC 2010 v C++&lt;/td&gt;&lt;td&gt;19.7&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;VC 2010 s C++&lt;/td&gt;&lt;td&gt;20.4&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;VC 2005 s C++&lt;/td&gt;&lt;td&gt;21&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;GCC 4.6 v C++&lt;/td&gt;&lt;td&gt;22.8&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;GCC 4.6 v C&lt;/td&gt;&lt;td&gt;23.5&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;VC 2005 v C&lt;/td&gt;&lt;td&gt;24&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;GCC 4.6 s C/C++&lt;/td&gt;&lt;td&gt;24.5&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;VC 2005 v C++&lt;/td&gt;&lt;td&gt;26&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;LLVM 3.0 s Rdbuf&lt;/td&gt;&lt;td&gt;31.5&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;GCC 4.6 s Rdbuf&lt;/td&gt;&lt;td&gt;32.5&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;GCC 4.6 s Copy&lt;/td&gt;&lt;td&gt;63&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;GCC 4.6 s Iterator&lt;/td&gt;&lt;td&gt;64.5&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;GCC 4.6 s Assign&lt;/td&gt;&lt;td&gt;68&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;GCC 4.6 v Copy&lt;/td&gt;&lt;td&gt;68&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;GCC 4.6 v Iterator&lt;/td&gt;&lt;td&gt;73&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;GCC 4.6 v Assign&lt;/td&gt;&lt;td&gt;81.8&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;LLVM 3.0 s Copy&lt;/td&gt;&lt;td&gt;97&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;LLVM 3.0 s Assign&lt;/td&gt;&lt;td&gt;102&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;LLVM 3.0 s Iterator&lt;/td&gt;&lt;td&gt;110&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;VC 2010 v Assign&lt;/td&gt;&lt;td&gt;159.5&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;VC 2010 v Copy&lt;/td&gt;&lt;td&gt;165.6&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;VC 2005 v Copy&lt;/td&gt;&lt;td&gt;172&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;VC 2010 s Rdbuf&lt;/td&gt;&lt;td&gt;176.2&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;VC 2010 v Iterator&lt;/td&gt;&lt;td&gt;180.6&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;VC 2005 s Rdbuf&lt;/td&gt;&lt;td&gt;199&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;VC 2005 s Iterator&lt;/td&gt;&lt;td&gt;209.3&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;VC 2005 s Assign&lt;/td&gt;&lt;td&gt;221&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;VC 2010 s Assign&lt;/td&gt;&lt;td&gt;222.8&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;VC 2010 s Iterator&lt;/td&gt;&lt;td&gt;224.4&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;VC 2010 s Copy&lt;/td&gt;&lt;td&gt;320&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;VC 2005 v Iterator&lt;/td&gt;&lt;td&gt;370&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;VC 2005 v Assign&lt;/td&gt;&lt;td&gt;378&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;VC 2005 s Copy&lt;/td&gt;&lt;td&gt;483.5&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;LLVM 3.0 v Iterator&lt;/td&gt;&lt;td&gt;860&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;LLVM 3.0 v Copy&lt;/td&gt;&lt;td&gt;930&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;LLVM 3.0 v Assign&lt;/td&gt;&lt;td&gt;1328&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/833174317742362874-1934168996693621718?l=insanecoding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://insanecoding.blogspot.com/feeds/1934168996693621718/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=833174317742362874&amp;postID=1934168996693621718' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/833174317742362874/posts/default/1934168996693621718'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/833174317742362874/posts/default/1934168996693621718'/><link rel='alternate' type='text/html' href='http://insanecoding.blogspot.com/2011/11/reading-in-entire-file-at-once-in-c.html' title='Reading in an entire file at once in C++, part 2'/><author><name>insane coder</name><uri>http://www.blogger.com/profile/06901386115570670209</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-833174317742362874.post-33811130938884247</id><published>2011-11-22T15:27:00.001-08:00</published><updated>2011-11-25T00:55:26.620-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='files'/><category scheme='http://www.blogger.com/atom/ns#' term='competition'/><category scheme='http://www.blogger.com/atom/ns#' term='good code'/><category scheme='http://www.blogger.com/atom/ns#' term='API'/><category scheme='http://www.blogger.com/atom/ns#' term='GCC'/><category scheme='http://www.blogger.com/atom/ns#' term='insane ideas'/><category scheme='http://www.blogger.com/atom/ns#' term='Optimization'/><title type='text'>How to read in a file in C++</title><content type='html'>So here's a simple question, what is the correct way to read in a file completely in C++?&lt;br /&gt;&lt;br /&gt;Various people have various solutions, those who use the C API, C++ API, or some variation of tricks with iterators and algorithms. Wondering which method is the fastest, I thought I might as well put the various options to the test, and the results were surprising.&lt;br /&gt;&lt;br /&gt;First, let me propose an API that we'll be using for the function. We'll send a function a C string (char *) of a filename, and we'll get back a C++ string (std::string) of the file contents. If the file cannot be opened, we'll throw an error why that is so. Of course you're welcome to change these functions to receive and return whatever format you prefer, but this is the prototype we'll be operating on:&lt;br /&gt;&lt;pre&gt;std::string get_file_contents(const char *filename);&lt;/pre&gt;&lt;br /&gt;Our first technique to consider is using the C API to read directly into a string. We'll open a file using fopen(), calculate the file size by seeking to the end, and then size a string appropriately. We'll read the contents into the string, and then return it.&lt;br /&gt;&lt;pre style="background-color:#F5F2D5"&gt;&lt;span style="color: #008000;"&gt;#include &amp;lt;string&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #008000;"&gt;#include &amp;lt;cstdio&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #008000;"&gt;#include &amp;lt;cerrno&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;std::string get_file_contents(&lt;/span&gt;&lt;span style="color: #800000;"&gt;const&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #800000;"&gt;char&lt;/span&gt;&lt;span style="color: #000000;"&gt; *filename)&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;{&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  std::FILE *fp = std::fopen(filename, &lt;/span&gt;&lt;span style="color: #dd0000;"&gt;"rb"&lt;/span&gt;&lt;span style="color: #000000;"&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;if&lt;/span&gt;&lt;span style="color: #000000;"&gt; (fp)&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  {&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;    std::string contents;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;    std::fseek(fp, &lt;/span&gt;&lt;span style="color: #0000ff;"&gt;0&lt;/span&gt;&lt;span style="color: #000000;"&gt;, SEEK_END);&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;    contents.resize(std::ftell(fp));&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;    std::rewind(fp);&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;    std::fread(&amp;amp;contents[&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;0&lt;/span&gt;&lt;span style="color: #000000;"&gt;], &lt;/span&gt;&lt;span style="color: #0000ff;"&gt;1&lt;/span&gt;&lt;span style="color: #000000;"&gt;, contents.size(), fp);&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;    std::fclose(fp);&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;    &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;return&lt;/span&gt;&lt;span style="color: #000000;"&gt;(contents);&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  }&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;throw&lt;/span&gt;&lt;span style="color: #000000;"&gt;(errno);&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;I'm dubbing this technique "method C". This is more or less the technique of any proficient C++ programmer who prefers C style I/O would look like.&lt;br /&gt;&lt;br /&gt;The next technique we'll review is basically the same idea, but using C++ streams instead.&lt;br /&gt;&lt;pre style="background-color:#F5F2D5"&gt;&lt;span style="color: #008000;"&gt;#include &amp;lt;fstream&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #008000;"&gt;#include &amp;lt;string&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #008000;"&gt;#include &amp;lt;cerrno&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;std::string get_file_contents(&lt;/span&gt;&lt;span style="color: #800000;"&gt;const&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #800000;"&gt;char&lt;/span&gt;&lt;span style="color: #000000;"&gt; *filename)&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;{&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  std::ifstream in(filename, std::ios::in | std::ios::binary);&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;if&lt;/span&gt;&lt;span style="color: #000000;"&gt; (in)&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  {&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;    std::string contents;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;    in.seekg(&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;0&lt;/span&gt;&lt;span style="color: #000000;"&gt;, std::ios::end);&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;    contents.resize(in.tellg());&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;    in.seekg(&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;0&lt;/span&gt;&lt;span style="color: #000000;"&gt;, std::ios::beg);&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;    in.read(&amp;amp;contents[&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;0&lt;/span&gt;&lt;span style="color: #000000;"&gt;], contents.size());&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;    in.close();&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;    &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;return&lt;/span&gt;&lt;span style="color: #000000;"&gt;(contents);&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  }&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;throw&lt;/span&gt;&lt;span style="color: #000000;"&gt;(errno);&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;I'm dubbing this technique "method C++". Again, more or less a straight forward C++ implementation based on the same principals as before.&lt;br /&gt;&lt;br /&gt;The next technique people consider is using istreambuf_iterator. This iterator is designed for really fast iteration out of stream buffers (files) in C++.&lt;br /&gt;&lt;pre style="background-color:#F5F2D5"&gt;&lt;span style="color: #008000;"&gt;#include &amp;lt;fstream&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #008000;"&gt;#include &amp;lt;streambuf&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #008000;"&gt;#include &amp;lt;string&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #008000;"&gt;#include &amp;lt;cerrno&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;std::string get_file_contents(&lt;/span&gt;&lt;span style="color: #800000;"&gt;const&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #800000;"&gt;char&lt;/span&gt;&lt;span style="color: #000000;"&gt; *filename)&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;{&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  std::ifstream in(filename, std::ios::in | std::ios::binary);&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;if&lt;/span&gt;&lt;span style="color: #000000;"&gt; (in)&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  {&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;    &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;return&lt;/span&gt;&lt;span style="color: #000000;"&gt;(std::string((std::istreambuf_iterator&amp;lt;&lt;/span&gt;&lt;span style="color: #800000;"&gt;char&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;gt;(in)), std::istreambuf_iterator&amp;lt;&lt;/span&gt;&lt;span style="color: #800000;"&gt;char&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;gt;()));&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  }&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;throw&lt;/span&gt;&lt;span style="color: #000000;"&gt;(errno);&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;This method is liked by many because of how little code is needed to implement it, and you can read a file directly into all sorts of containers, not just strings. The method was also popularized by the Effective STL book. I'm dubbing the technique "method iterator".&lt;br /&gt;&lt;br /&gt;Now some have looked at the last technique, and felt it could be optimized further, since if the string has an idea in advance how big it needs to be, it will reallocate less. So the idea is to reserve the size of the string, then pull the data in.&lt;br /&gt;&lt;pre style="background-color:#F5F2D5"&gt;&lt;span style="color: #008000;"&gt;#include &amp;lt;fstream&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #008000;"&gt;#include &amp;lt;streambuf&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #008000;"&gt;#include &amp;lt;string&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #008000;"&gt;#include &amp;lt;cerrno&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;std::string get_file_contents(&lt;/span&gt;&lt;span style="color: #800000;"&gt;const&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #800000;"&gt;char&lt;/span&gt;&lt;span style="color: #000000;"&gt; *filename)&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;{&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  std::ifstream in(filename, std::ios::in | std::ios::binary);&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;if&lt;/span&gt;&lt;span style="color: #000000;"&gt; (in)&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  {&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;    std::string contents;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;    in.seekg(&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;0&lt;/span&gt;&lt;span style="color: #000000;"&gt;, std::ios::end);&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;    contents.reserve(in.tellg());&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;    in.seekg(&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;0&lt;/span&gt;&lt;span style="color: #000000;"&gt;, std::ios::beg);&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;    contents.assign((std::istreambuf_iterator&amp;lt;&lt;/span&gt;&lt;span style="color: #800000;"&gt;char&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;gt;(in)), std::istreambuf_iterator&amp;lt;&lt;/span&gt;&lt;span style="color: #800000;"&gt;char&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;gt;());&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;    in.close();&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;    &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;return&lt;/span&gt;&lt;span style="color: #000000;"&gt;(contents);&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  }&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;throw&lt;/span&gt;&lt;span style="color: #000000;"&gt;(errno);&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;I will call this technique "method assign", since it uses the string's assign function.&lt;br /&gt;&lt;br /&gt;Some have questioned the previous function, as assign() in some implementations may very well replace the internal buffer, and therefore not benefit from reserving. Better to call push_back() instead, which will keep the existing buffer if no reallocation is needed.&lt;br /&gt;&lt;pre style="background-color:#F5F2D5"&gt;&lt;span style="color: #008000;"&gt;#include &amp;lt;fstream&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #008000;"&gt;#include &amp;lt;streambuf&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #008000;"&gt;#include &amp;lt;string&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #008000;"&gt;#include &amp;lt;algorithm&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #008000;"&gt;#include &amp;lt;iterator&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #008000;"&gt;#include &amp;lt;cerrno&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;std::string get_file_contents(&lt;/span&gt;&lt;span style="color: #800000;"&gt;const&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #800000;"&gt;char&lt;/span&gt;&lt;span style="color: #000000;"&gt; *filename)&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;{&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  std::ifstream in(filename, std::ios::in | std::ios::binary);&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;if&lt;/span&gt;&lt;span style="color: #000000;"&gt; (in)&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  {&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;    std::string contents;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;    in.seekg(&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;0&lt;/span&gt;&lt;span style="color: #000000;"&gt;, std::ios::end);&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;    contents.reserve(in.tellg());&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;    in.seekg(&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;0&lt;/span&gt;&lt;span style="color: #000000;"&gt;, std::ios::beg);&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;    std::copy((std::istreambuf_iterator&amp;lt;&lt;/span&gt;&lt;span style="color: #800000;"&gt;char&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;gt;(in)), std::istreambuf_iterator&amp;lt;&lt;/span&gt;&lt;span style="color: #800000;"&gt;char&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;gt;(), std::back_inserter(contents));&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;    in.close();&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;    &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;return&lt;/span&gt;&lt;span style="color: #000000;"&gt;(contents);&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  }&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;throw&lt;/span&gt;&lt;span style="color: #000000;"&gt;(errno);&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;Combining std::copy() and std::back_inserter(), we can achieve our goal. I'm labeling this technique "method copy".&lt;br /&gt;&lt;br /&gt;Lastly, some want to try another approach entirely. C++ streams have some very fast copying to another stream via operator&amp;lt;&amp;lt; on their internal buffers. Therefore, we can copy directly into a string stream, and then return the string that string stream uses.&lt;br /&gt;&lt;pre style="background-color:#F5F2D5"&gt;&lt;span style="color: #008000;"&gt;#include &amp;lt;fstream&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #008000;"&gt;#include &amp;lt;sstream&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #008000;"&gt;#include &amp;lt;string&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #008000;"&gt;#include &amp;lt;cerrno&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;std::string get_file_contents(&lt;/span&gt;&lt;span style="color: #800000;"&gt;const&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #800000;"&gt;char&lt;/span&gt;&lt;span style="color: #000000;"&gt; *filename)&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;{&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  std::ifstream in(filename, std::ios::in | std::ios::binary);&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;if&lt;/span&gt;&lt;span style="color: #000000;"&gt; (in)&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  {&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;    std::ostringstream contents;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;    contents &amp;lt;&amp;lt; in.rdbuf();&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;    in.close();&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;    &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;return&lt;/span&gt;&lt;span style="color: #000000;"&gt;(contents.str());&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  }&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;throw&lt;/span&gt;&lt;span style="color: #000000;"&gt;(errno);&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;We'll call this technique "method rdbuf".&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Now which is the fastest method to use if all you actually want to do is read the file into a string and return it? The exact speeds in relation to each other may vary from one implementation to another, but the overall margins between the various techniques should be similar.&lt;br /&gt;&lt;br /&gt;I conducted my tests with libstdc++ and GCC 4.6, what you see may vary from this.&lt;br /&gt;&lt;br /&gt;I tested with multiple megabyte files, reading in one after another, and repeated the tests a dozen times and averaged the results.&lt;table&gt;&lt;br /&gt;&lt;tr&gt;&lt;th&gt;Method&lt;/th&gt;&lt;th&gt;Duration&lt;/th&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;C&lt;/td&gt;&lt;td&gt;24.5&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;C++&lt;/td&gt;&lt;td&gt;24.5&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;Iterator&lt;/td&gt;&lt;td&gt;64.5&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;Assign&lt;/td&gt;&lt;td&gt;68&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;Copy&lt;/td&gt;&lt;td&gt;62.5&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;Rdbuf&lt;/td&gt;&lt;td&gt;32.5&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;Ordered by speed:&lt;table&gt;&lt;br /&gt;&lt;tr&gt;&lt;th&gt;Method&lt;/th&gt;&lt;th&gt;Duration&lt;/th&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;C/C++&lt;/td&gt;&lt;td&gt;24.5&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;Rdbuf&lt;/td&gt;&lt;td&gt;32.5&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;Copy&lt;/td&gt;&lt;td&gt;62.5&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;Iterator&lt;/td&gt;&lt;td&gt;64.5&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;Assign&lt;/td&gt;&lt;td&gt;68&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;These results are rather interesting. There was no speed difference at all whether using the C or C++ API for reading a file. This should be obvious to us all, but yet many people strangely think that the C API has less overhead. The straight forward vanilla methods were also faster than anything involving iterators.&lt;br /&gt;&lt;br /&gt;C++ stream to stream copying is really fast. It probably only took a bit longer than the vanilla method due to some reallocations needed. If you're doing disk file to disk file though, you probably want to consider this option, and go directly from in stream to out stream.&lt;br /&gt;&lt;br /&gt;Using the istreambuf_iterator methods while popular and concise are actually rather slow. Sure they're faster than istream_iterators (with skipping turned off), but they can't compete with more direct methods.&lt;br /&gt;&lt;br /&gt;A C++ string's internal assign() function, at least in libstdc++, seems to throw away the existing buffer (at the time of this writing), so reserving then assigning is rather useless. On the other hand, reading directly into a string, or a different container for that matter, isn't necessarily your most optimal solution where iterators are concerned. Using the external std::copy() function, along with back inserting after reservation is faster than straight up initialization. You might want to consider this method for inserting into some other containers. In fact, I found that std::copy() of istreambuf_iterators with back inserter into an std::deque to be faster than straight up initialization (81 vs 88.5), despite a Deque not being able to reserve room in advance (nor does such make sense with a Deque).&lt;br /&gt;&lt;br /&gt;I also found this to be a cute way to get a file into a container backwards, despite a Deque being rather useless for working with file contents.&lt;br /&gt;&lt;pre&gt;std::deque&amp;lt;char&amp;gt; contents;&lt;br /&gt;std::copy((std::istreambuf_iterator&amp;lt;char&amp;gt;(in)), std::istreambuf_iterator&amp;lt;char&amp;gt;(), std::front_inserter(contents));&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Now go out there and speed up your applications!&lt;br /&gt;&lt;br /&gt;If there's any demand, I'll see about performing these tests with other C++ implementations.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/833174317742362874-33811130938884247?l=insanecoding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://insanecoding.blogspot.com/feeds/33811130938884247/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=833174317742362874&amp;postID=33811130938884247' title='11 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/833174317742362874/posts/default/33811130938884247'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/833174317742362874/posts/default/33811130938884247'/><link rel='alternate' type='text/html' href='http://insanecoding.blogspot.com/2011/11/how-to-read-in-file-in-c.html' title='How to read in a file in C++'/><author><name>insane coder</name><uri>http://www.blogger.com/profile/06901386115570670209</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>11</thr:total></entry><entry><id>tag:blogger.com,1999:blog-833174317742362874.post-474153468529086324</id><published>2011-11-19T12:18:00.001-08:00</published><updated>2011-11-19T12:42:17.228-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='bugs'/><category scheme='http://www.blogger.com/atom/ns#' term='pure failure'/><category scheme='http://www.blogger.com/atom/ns#' term='compatibility'/><category scheme='http://www.blogger.com/atom/ns#' term='linux'/><category scheme='http://www.blogger.com/atom/ns#' term='debian'/><category scheme='http://www.blogger.com/atom/ns#' term='bad code'/><category scheme='http://www.blogger.com/atom/ns#' term='modconf'/><title type='text'>Making modconf work with Linux 3</title><content type='html'>&lt;p&gt;If you want a nice curses based GUI to add and remove modules from Linux on the fly, you probably used modconf. They say it's deprecated, but they still haven't made anything to replace it.&lt;/p&gt;&lt;p&gt;I noticed that it stopped working on Linux 3.&lt;/p&gt;&lt;p&gt;The problem is as follows, the configuration scripts that come with modconf generally look to see if you're using Linux 2.0 - 2.4 and do one thing, and do another for 2.5 and up. They generally check just the second digit, so now with Linux "3.0" it thinks you're using 2.0 and does something for &amp;lt;2.5 when it should be using the &amp;gt;=2.5 method.&lt;/p&gt;&lt;p&gt;Edit &lt;i&gt;/usr/share/modconf/params&lt;/i&gt;&lt;br /&gt;Look for:&lt;br /&gt;&lt;pre&gt;case "$(uname -r | cut -f2 -d.)" in&lt;br /&gt;  0|1|2|3|4)&lt;br /&gt;  CFGFILE=$Target/etc/modules.conf&lt;br /&gt;  MODUTILSDIR=$Target/etc/modutils&lt;br /&gt;  ;;&lt;br /&gt;  *)&lt;br /&gt;  CFGFILE=$Target/etc/modprobe.d&lt;br /&gt;  MODUTILSDIR=$Target/etc/modprobe.d&lt;br /&gt;  ;;&lt;br /&gt;esac&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Replace it with:&lt;br /&gt;&lt;pre&gt;CFGFILE=$Target/etc/modprobe.d&lt;br /&gt;MODUTILSDIR=$Target/etc/modprobe.d&lt;br /&gt;&lt;/pre&gt;&lt;/p&gt;&lt;p&gt;Edit &lt;i&gt;/usr/share/modconf/util&lt;/i&gt;&lt;br /&gt;Look for:&lt;br /&gt;&lt;pre&gt;  case "$(uname -r | cut -f2 -d.)" in&lt;br /&gt;     0|1|2|3|4)&lt;br /&gt;     modsuffix=".o"&lt;br /&gt;     using_mit=1&lt;br /&gt;     ;;&lt;br /&gt;     *)  modsuffix=".ko" ;;&lt;br /&gt;  esac&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Replace it with:&lt;br /&gt;&lt;pre&gt;modsuffix=".ko"&lt;br /&gt;&lt;/pre&gt;&lt;/p&gt;&lt;p&gt;And that's all there is to it!&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/833174317742362874-474153468529086324?l=insanecoding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://insanecoding.blogspot.com/feeds/474153468529086324/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=833174317742362874&amp;postID=474153468529086324' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/833174317742362874/posts/default/474153468529086324'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/833174317742362874/posts/default/474153468529086324'/><link rel='alternate' type='text/html' href='http://insanecoding.blogspot.com/2011/11/making-modconf-work-with-linux-3.html' title='Making modconf work with Linux 3'/><author><name>insane coder</name><uri>http://www.blogger.com/profile/06901386115570670209</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-833174317742362874.post-4360871671430803612</id><published>2011-10-25T18:24:00.000-07:00</published><updated>2011-10-25T19:20:21.180-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='good code'/><category scheme='http://www.blogger.com/atom/ns#' term='Ancient Coding Ideas'/><category scheme='http://www.blogger.com/atom/ns#' term='insane ideas'/><category scheme='http://www.blogger.com/atom/ns#' term='language'/><title type='text'>A stronger C/C++ Preprocesser</title><content type='html'>Ever felt you needed some preprocessing to generate some C/C++ code for you, but the C preprocesssor is too lacking? Say for example you wanted to include &lt;b&gt;part&lt;/b&gt; of another file, or include output from an application. Perhaps the compile should be based on some data found on a remote server? Well, there are stronger preprocessors which work for C/C++, such as PHP.&lt;br /&gt;&lt;br /&gt;Here's an example:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;/tmp&amp;gt; php test.cpp.php | g++ -x c++ -Wall -o test -&lt;br /&gt;/tmp&amp;gt; ./test&lt;br /&gt;Hello 0&lt;br /&gt;Hello 1&lt;br /&gt;Hello 2&lt;br /&gt;Hello 3&lt;br /&gt;Hello 4&lt;br /&gt;/tmp&amp;gt; cat test.cpp.php&lt;br /&gt;#include &amp;lt;iostream&amp;gt;&lt;br /&gt;int main()&lt;br /&gt;{&lt;br /&gt;  &amp;lt;?php for ($i = 0; $i &lt; 5; ++$i) { echo 'std::cout &lt;&lt; "Hello ', $i, '" &lt;&lt; std::endl;'; } ?&amp;gt;&lt;br /&gt;  return(0);&lt;br /&gt;}&lt;br /&gt;/tmp&amp;gt;&lt;br /&gt;&lt;/pre&gt;Here's a more interesting example:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;/tmp&amp;gt; php weather_example.c.php | gcc -x c -Wall -o weather_example -&lt;br /&gt;/tmp&amp;gt; ./weather_example&lt;br /&gt;Hi, when I was compiled, the weather here in New York City was 57F&lt;br /&gt;/tmp&amp;gt; cat weather_example.c.php&lt;br /&gt;&amp;lt;?php&lt;br /&gt;$w = file_get_contents('http://www.google.com/ig/api?weather=New+York+City');&lt;br /&gt;$f = '&amp;lt;temp_f data="';&lt;br /&gt;echo '#define __WEATHER__ ', (int)substr($w, strpos($w, $f)+strlen($f)), 'U', "\n";&lt;br /&gt;?&gt;&lt;br /&gt;#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;int main()&lt;br /&gt;{&lt;br /&gt;  printf("Hi, when I was compiled, the weather here in New York City was %uF\n", __WEATHER__);&lt;br /&gt;  return(0);&lt;br /&gt;}&lt;br /&gt;/tmp&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/833174317742362874-4360871671430803612?l=insanecoding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://insanecoding.blogspot.com/feeds/4360871671430803612/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=833174317742362874&amp;postID=4360871671430803612' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/833174317742362874/posts/default/4360871671430803612'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/833174317742362874/posts/default/4360871671430803612'/><link rel='alternate' type='text/html' href='http://insanecoding.blogspot.com/2011/10/stronger-cc-preprocesser.html' title='A stronger C/C++ Preprocesser'/><author><name>insane coder</name><uri>http://www.blogger.com/profile/06901386115570670209</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-833174317742362874.post-6885910511143196800</id><published>2011-10-16T06:26:00.000-07:00</published><updated>2011-10-16T06:38:46.531-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='code search'/><category scheme='http://www.blogger.com/atom/ns#' term='pure failure'/><category scheme='http://www.blogger.com/atom/ns#' term='API'/><category scheme='http://www.blogger.com/atom/ns#' term='searching'/><category scheme='http://www.blogger.com/atom/ns#' term='Google'/><category scheme='http://www.blogger.com/atom/ns#' term='Optimization'/><title type='text'>Goodbye Google</title><content type='html'>Google &lt;a href="http://googleblog.blogspot.com/2011/10/fall-sweep.html"&gt;announced&lt;/a&gt; they're shutting down &lt;a href="http://www.google.com/codesearch"&gt;Code Search&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;I found Google Code Search to be invaluable in the kind of work I do. I saved tons of time by being able to find existing code for something tricky already invented. Or I could compare multiple implementations for things to learn about what different techniques there are for various operations and learn immensely from their pros and cons. If you're reimplementing something yourself, it's also nice to be easily able to find tests cases and other things with Google Code Search.&lt;br /&gt;&lt;br /&gt;Now all that is going away. Are there any feasible alternatives? Do we need to start a competing search engine? What are programmers to do when Google cuts the number one online tool for researching code?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/833174317742362874-6885910511143196800?l=insanecoding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://insanecoding.blogspot.com/feeds/6885910511143196800/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=833174317742362874&amp;postID=6885910511143196800' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/833174317742362874/posts/default/6885910511143196800'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/833174317742362874/posts/default/6885910511143196800'/><link rel='alternate' type='text/html' href='http://insanecoding.blogspot.com/2011/10/goodbye-google.html' title='Goodbye Google'/><author><name>insane coder</name><uri>http://www.blogger.com/profile/06901386115570670209</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-833174317742362874.post-2767580020236296293</id><published>2011-06-20T06:33:00.001-07:00</published><updated>2011-06-20T06:39:12.801-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='non rectangular array'/><category scheme='http://www.blogger.com/atom/ns#' term='C++ 2011'/><category scheme='http://www.blogger.com/atom/ns#' term='GCC'/><category scheme='http://www.blogger.com/atom/ns#' term='initializer lists'/><title type='text'>C++ 2011 and non rectangular arrays</title><content type='html'>Ever wanted to make a non rectangular array? Meaning for example, some multidimensional array where a[0] has 3 members and a[1] has 5 members, and so on.&lt;br /&gt;&lt;br /&gt;You could do it with first building up the outermost array, and then add on each subarray separately, but you can't do it all in one shot at initialization time.&lt;br /&gt;&lt;br /&gt;But enter C++ 2011 with initializer lists. You can initialize vectors of vectors with as many members at each level you want.&lt;br /&gt;&lt;br /&gt;This works:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt; a&lt;br /&gt;(&lt;br /&gt;  {&lt;br /&gt;    { 1, },&lt;br /&gt;    { 1, 2, },&lt;br /&gt;    { 1, 2, 3, },&lt;br /&gt;    { 1, 2, 3, 4, 5, 6, 7, },&lt;br /&gt;    { 1, 2, },&lt;br /&gt;  }&lt;br /&gt;);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;a.size() is 5, a[0].size() is 1, a[1].size() is 2, and so on.&lt;br /&gt;&lt;br /&gt;Here's a complete example:&lt;br /&gt;&lt;pre style="background-color: #F5F2D5"&gt;&lt;span style="color: #008000;"&gt;#include &amp;lt;iostream&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #008000;"&gt;#include &amp;lt;vector&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;using&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;namespace&lt;/span&gt;&lt;span style="color: #000000;"&gt; std;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;vector&amp;lt;vector&amp;lt;&lt;/span&gt;&lt;span style="color: #800000;"&gt;int&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;gt;&amp;gt; a&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;(&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  {&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;    { &lt;/span&gt;&lt;span style="color: #0000ff;"&gt;1&lt;/span&gt;&lt;span style="color: #000000;"&gt;, },&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;    { &lt;/span&gt;&lt;span style="color: #0000ff;"&gt;1&lt;/span&gt;&lt;span style="color: #000000;"&gt;, &lt;/span&gt;&lt;span style="color: #0000ff;"&gt;2&lt;/span&gt;&lt;span style="color: #000000;"&gt;, },&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;    { &lt;/span&gt;&lt;span style="color: #0000ff;"&gt;1&lt;/span&gt;&lt;span style="color: #000000;"&gt;, &lt;/span&gt;&lt;span style="color: #0000ff;"&gt;2&lt;/span&gt;&lt;span style="color: #000000;"&gt;, &lt;/span&gt;&lt;span style="color: #0000ff;"&gt;3&lt;/span&gt;&lt;span style="color: #000000;"&gt;, },&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;    { &lt;/span&gt;&lt;span style="color: #0000ff;"&gt;1&lt;/span&gt;&lt;span style="color: #000000;"&gt;, &lt;/span&gt;&lt;span style="color: #0000ff;"&gt;2&lt;/span&gt;&lt;span style="color: #000000;"&gt;, &lt;/span&gt;&lt;span style="color: #0000ff;"&gt;3&lt;/span&gt;&lt;span style="color: #000000;"&gt;, &lt;/span&gt;&lt;span style="color: #0000ff;"&gt;4&lt;/span&gt;&lt;span style="color: #000000;"&gt;, &lt;/span&gt;&lt;span style="color: #0000ff;"&gt;5&lt;/span&gt;&lt;span style="color: #000000;"&gt;, &lt;/span&gt;&lt;span style="color: #0000ff;"&gt;6&lt;/span&gt;&lt;span style="color: #000000;"&gt;, &lt;/span&gt;&lt;span style="color: #0000ff;"&gt;7&lt;/span&gt;&lt;span style="color: #000000;"&gt;, },&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;    { &lt;/span&gt;&lt;span style="color: #0000ff;"&gt;1&lt;/span&gt;&lt;span style="color: #000000;"&gt;, &lt;/span&gt;&lt;span style="color: #0000ff;"&gt;2&lt;/span&gt;&lt;span style="color: #000000;"&gt;, },&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  }&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #800000;"&gt;void&lt;/span&gt;&lt;span style="color: #000000;"&gt; print(&lt;/span&gt;&lt;span style="color: #800000;"&gt;int&lt;/span&gt;&lt;span style="color: #000000;"&gt; t)&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;{&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  cout &amp;lt;&amp;lt; t &amp;lt;&amp;lt; &lt;/span&gt;&lt;span style="color: #dd0000;"&gt;", "&lt;/span&gt;&lt;span style="color: #000000;"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;template&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;typename&lt;/span&gt;&lt;span style="color: #000000;"&gt; T&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #800000;"&gt;void&lt;/span&gt;&lt;span style="color: #000000;"&gt; print(&lt;/span&gt;&lt;span style="color: #800000;"&gt;const&lt;/span&gt;&lt;span style="color: #000000;"&gt; T &amp;amp;t)&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;{&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;for&lt;/span&gt;&lt;span style="color: #000000;"&gt; (&lt;/span&gt;&lt;span style="color: #800000;"&gt;auto&lt;/span&gt;&lt;span style="color: #000000;"&gt; i = t.begin(); i != t.end(); ++i)&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  {&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;    print(*i);&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  }&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  cout &amp;lt;&amp;lt; &lt;/span&gt;&lt;span style="color: #ff00ff;"&gt;'\n'&lt;/span&gt;&lt;span style="color: #000000;"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #800000;"&gt;int&lt;/span&gt;&lt;span style="color: #000000;"&gt; main()&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;{&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  print(a);&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;return&lt;/span&gt;&lt;span style="color: #000000;"&gt;(&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;0&lt;/span&gt;&lt;span style="color: #000000;"&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Output:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;/tmp&amp;gt; g++-4.4 -Wall -o test test.cpp -std=c++0x&lt;br /&gt;/tmp&amp;gt; ./test&lt;br /&gt;1,&lt;br /&gt;1, 2,&lt;br /&gt;1, 2, 3,&lt;br /&gt;1, 2, 3, 4, 5, 6, 7,&lt;br /&gt;1, 2,&lt;br /&gt;&lt;br /&gt;/tmp&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/833174317742362874-2767580020236296293?l=insanecoding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://insanecoding.blogspot.com/feeds/2767580020236296293/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=833174317742362874&amp;postID=2767580020236296293' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/833174317742362874/posts/default/2767580020236296293'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/833174317742362874/posts/default/2767580020236296293'/><link rel='alternate' type='text/html' href='http://insanecoding.blogspot.com/2011/06/c-2011-and-non-rectangular-arrays.html' title='C++ 2011 and non rectangular arrays'/><author><name>insane coder</name><uri>http://www.blogger.com/profile/06901386115570670209</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-833174317742362874.post-8043809126962101793</id><published>2011-06-20T05:22:00.000-07:00</published><updated>2011-06-20T05:30:57.656-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='C++ 2011'/><category scheme='http://www.blogger.com/atom/ns#' term='GCC'/><category scheme='http://www.blogger.com/atom/ns#' term='lambda functions'/><category scheme='http://www.blogger.com/atom/ns#' term='c99'/><category scheme='http://www.blogger.com/atom/ns#' term='__func__'/><title type='text'>C++ 2011 and __func__</title><content type='html'>So what happens to __func__ in different scopes? How about GCC's extension for pretty function names?&lt;br /&gt;&lt;br /&gt;&lt;pre style="background-color:#F5F2D5;"&gt;&lt;span style="color: #008000;"&gt;#include &amp;lt;iostream&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;using&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;namespace&lt;/span&gt;&lt;span style="color: #000000;"&gt; std;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;namespace&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;{&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="color: #800000;"&gt;void&lt;/span&gt;&lt;span style="color: #000000;"&gt; f()&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  {&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;    &lt;/span&gt;&lt;span style="color: #800000;"&gt;auto&lt;/span&gt;&lt;span style="color: #000000;"&gt; func = []()-&amp;gt;&lt;/span&gt;&lt;span style="color: #800000;"&gt;const&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #800000;"&gt;char&lt;/span&gt;&lt;span style="color: #000000;"&gt; *{ &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;return&lt;/span&gt;&lt;span style="color: #000000;"&gt;(__func__); };&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;    &lt;/span&gt;&lt;span style="color: #800000;"&gt;auto&lt;/span&gt;&lt;span style="color: #000000;"&gt; func2 = []()-&amp;gt;&lt;/span&gt;&lt;span style="color: #800000;"&gt;const&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #800000;"&gt;char&lt;/span&gt;&lt;span style="color: #000000;"&gt; *{ &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;return&lt;/span&gt;&lt;span style="color: #000000;"&gt;(__PRETTY_FUNCTION__); }; &lt;/span&gt;&lt;span style="font-style: italic;color: #808080;"&gt;//GCC extension&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;    cout &amp;lt;&amp;lt; func() &amp;lt;&amp;lt; &lt;/span&gt;&lt;span style="color: #ff00ff;"&gt;'\n'&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;         &amp;lt;&amp;lt; func2() &amp;lt;&amp;lt; &lt;/span&gt;&lt;span style="color: #ff00ff;"&gt;'\n'&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;         &amp;lt;&amp;lt; __func__ &amp;lt;&amp;lt; &lt;/span&gt;&lt;span style="color: #ff00ff;"&gt;'\n'&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;         &amp;lt;&amp;lt; __PRETTY_FUNCTION__ &amp;lt;&amp;lt; endl;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  }&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #800000;"&gt;int&lt;/span&gt;&lt;span style="color: #000000;"&gt; main()&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;{&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  f();&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  cout &amp;lt;&amp;lt; __func__ &amp;lt;&amp;lt; &lt;/span&gt;&lt;span style="color: #ff00ff;"&gt;'\n'&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;       &amp;lt;&amp;lt; __PRETTY_FUNCTION__ &amp;lt;&amp;lt; endl;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;return&lt;/span&gt;&lt;span style="color: #000000;"&gt;(&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;0&lt;/span&gt;&lt;span style="color: #000000;"&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Output:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;/tmp&amp;gt; g++-4.5 -Wall -o test test.cpp -std=c++0x&lt;br /&gt;/tmp&amp;gt; ./test&lt;br /&gt;operator()&lt;br /&gt;&amp;lt;unnamed&gt;::f()::&amp;lt;lambda()&amp;gt;&lt;br /&gt;f&lt;br /&gt;void&amp;lt;unnamed&amp;gt;::f()&lt;br /&gt;main&lt;br /&gt;int main()&lt;br /&gt;/tmp&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre&gt;&lt;br /&gt;/tmp&amp;gt; g++-4.6 -Wall -o test test.cpp -std=c++0x&lt;br /&gt;/tmp&amp;gt; ./test&lt;br /&gt;operator()&lt;br /&gt;{anonymous}::f()::&amp;lt;lambda()&amp;gt;&lt;br /&gt;f&lt;br /&gt;void {anonymous}::f()&lt;br /&gt;main&lt;br /&gt;int main()&lt;br /&gt;/tmp&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/833174317742362874-8043809126962101793?l=insanecoding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://insanecoding.blogspot.com/feeds/8043809126962101793/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=833174317742362874&amp;postID=8043809126962101793' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/833174317742362874/posts/default/8043809126962101793'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/833174317742362874/posts/default/8043809126962101793'/><link rel='alternate' type='text/html' href='http://insanecoding.blogspot.com/2011/06/c-2011-and-func.html' title='C++ 2011 and __func__'/><author><name>insane coder</name><uri>http://www.blogger.com/profile/06901386115570670209</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-833174317742362874.post-6666768773740268340</id><published>2011-04-09T11:41:00.000-07:00</published><updated>2011-04-09T15:33:40.976-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='bugs'/><category scheme='http://www.blogger.com/atom/ns#' term='signed'/><category scheme='http://www.blogger.com/atom/ns#' term='pure failure'/><category scheme='http://www.blogger.com/atom/ns#' term='Mozilla'/><category scheme='http://www.blogger.com/atom/ns#' term='compatibility'/><category scheme='http://www.blogger.com/atom/ns#' term='secure'/><category scheme='http://www.blogger.com/atom/ns#' term='Google'/><category scheme='http://www.blogger.com/atom/ns#' term='Portability'/><category scheme='http://www.blogger.com/atom/ns#' term='protocols'/><title type='text'>The failure of fragmented security</title><content type='html'>With recent attacks against &lt;a href="http://en.wikipedia.org/wiki/Transport_Layer_Security"&gt;SSL/TLS&lt;/a&gt; and &lt;a href="http://en.wikipedia.org/wiki/Public_key_certificate"&gt;certificates&lt;/a&gt;, everyone has been thinking a lot about security. What can we do to prevent security problems in the future?&lt;br /&gt;&lt;br /&gt;The problem really stems from the fact that our different security components are separate from one another, and don't entirely see eye to eye, leaving gaps for attackers to walk right on through. The current certificate system for certifying the identity of a website is flawed in theory, and in its implementation in many browsers.&lt;br /&gt;&lt;br /&gt;The current system works as follows: An entity submits proof of ownership of the domain(s) it owns to one of hundreds of &lt;a href="http://en.wikipedia.org/wiki/Certificate_authority"&gt;certificate authorities&lt;/a&gt; out there, who follow some kind of verification process, and then proceed to give a certificate identifying the site to that entity. This certificate is digitally signed by the certificate authority itself using their private unknown keys. Since no one but the certificate authority itself has their private keys, they're the only ones able to sign certificates in their own name. Browsers ship with a certificate bundle identifying the certificate authorities they trust. In this way, when you see a site with a certificate signed by a known certificate authority, you know it's the site you intended to visit.&lt;br /&gt;&lt;br /&gt;Except there's some flaws with this idea. If terrorists wanted to, they could attack a certificate authority's physical headquarters and steal their private keys from their server and sign whatever they want for whichever domain they wish. Or, hackers could hack into machines remotely and perhaps get lucky and find some private keys on them. Or, anyone could start their own certificate authority. It really isn't that hard. Once your new authority becomes trusted by the various browsers, you can proceed to generate certificates for any domain desired.&lt;br /&gt;&lt;br /&gt;This entire system has multiple points of failure. Further compounding the issue is that several "trusted" certificate authorities also are in themselves ISPs or run various links in the vast internet. Having both components in your control allow you to impersonate any site for any information passing through your systems. America Online for example is both a trusted certificate authority and an ISP, and anyone who works there and has access to their infrastructure and private keys can view all HTTPS encrypted data passing through their network as unencrypted. Want to buy something with your credit card online? You might want to &lt;a href="http://en.wikipedia.org/wiki/Traceroute"&gt;traceroute&lt;/a&gt; your connection first and ensure no one along the way is also a certificate authority your browser trusts.&lt;br /&gt;&lt;br /&gt;In order to mitigate a certificate authority signing something it shouldn't have, they invented &lt;a href="http://en.wikipedia.org/wiki/Revocation_list"&gt;Certificate Revocation Lists&lt;/a&gt;. Where an authority can revoke specific certificates it once signed, since every certificate also has an ID number associated with it. But, some browsers don't even bother checking these lists. Further, some browsers which make use of CRLs and their friends, resume as if nothing happened if they couldn't access a CRL for some reason. Further, these CRLs are subject to the same security problems just described for domains in general. How do I know this is indeed the real CRL? Also, browsers themselves don't have CRLs for the root certificates they ship with, so they are unable to revoke a certificate of a rogue CA if they need to.&lt;br /&gt;&lt;br /&gt;But in reality, this entire system is flawed from the ground up. It's so flawed, it doesn't even make the slightest bit of sense. Imagine the following scenario where my boss asks me to inform him of all purchasing details for our web presence needs, and explain why they're needed.&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;&amp;lt;Me&amp;gt; Okay, we're going to need $35 a year to &lt;a href="http://en.wikipedia.org/wiki/Domain_registry"&gt;register all the domains&lt;/a&gt; we want for our company, such as company.com and company.net and so on.&lt;br /&gt;&amp;lt;Him&amp;gt; Sure, that's fine, what else?&lt;br /&gt;&amp;lt;Me&amp;gt; Then we're going to need $200 a year for each domain for certificates.&lt;br /&gt;&amp;lt;Him&amp;gt; Why do we need these certificates?&lt;br /&gt;&amp;lt;Me&amp;gt; To prove that we own the domain in question.&lt;br /&gt;&amp;lt;Him&amp;gt; Prove it? Why?&lt;br /&gt;&amp;lt;Me&amp;gt; Browsers like Internet Explorer and Firefox won't realize when they visit our domain that its really our domain, and not some hacker out there trying to impersonate us.&lt;br /&gt;&amp;lt;Him&amp;gt; So if we don't buy these certificates, hackers will be able to get the domain names registered as their own instead of ours?&lt;br /&gt;&amp;lt;Me&amp;gt; No, the domain names are protected by a central authority, they know that we own them, and we tell them to point the domains at our servers, but hackers in between our customer's browser and our server can hijack the connection and make believe they're us without a certificate.&lt;br /&gt;&amp;lt;Him&amp;gt; I don't get it, why can't our customer's browser just check the domain registry and make sure the server they reach is the one we told the domain registry about? Why do we need to buy something from a 3rd party?&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;This seems strange to you? He's absolutely right. Why can't the &lt;a href="http://en.wikipedia.org/wiki/Root_nameserver"&gt;hierarchy&lt;/a&gt; for domain management also distribute the public keys for our servers? The systems will need to be modified to combine several components and have encryption at each level, but does anything else make an ounce of sense?&lt;br /&gt;&lt;br /&gt;Imagine you wanted to buy some property. You have your lawyer, accountant, realtor, and other people directly related to the purchase. After everything is taken care of, and you submit forms to city hall and everything else, you then go down to Joe's House of Fine Refrigerators and have him give you a signed deed that you indeed own the property in question. Makes a lot of sense, right?&lt;br /&gt;&lt;br /&gt;Now you call a construction company down to work on your new property, say to merge it with the property next door to it. They want proof you own both properties before beginning. What do you do? You pull out your deed from Joe's House of Fine Refrigerators.&lt;br /&gt;&lt;br /&gt;This is the exact state of internet security today. This problem is even pervasive down to every level of infrastructure we use.&lt;br /&gt;&lt;br /&gt;Take &lt;a href="http://en.wikipedia.org/wiki/HTTP_cookie"&gt;cookies&lt;/a&gt; for example, the system it uses to match domain names runs completely counter to how the &lt;a href="http://en.wikipedia.org/wiki/Domain_Name_System"&gt;domain name system&lt;/a&gt; works. It's actually impossible for any browser to properly know for every set of domains in existence whether they're paired or not when it comes to handling cookies for them. It will either fail to submit cookies to some sites that it should, or submit cookies to some sites it shouldn't. Some browsers try to solve this problem with a massive hack, a &lt;a href="http://publicsuffix.org/"&gt;list of domains that cookies should know are or aren't paired together&lt;/a&gt;, which is also incomplete, and needs never ending updates. Without the list, the only difference is that the browser is just wrong more often than without it.&lt;br /&gt;&lt;br /&gt;Really, &lt;a href="http://insanecoding.blogspot.com/2009/11/malicious-hackers-are-not-out-there.html"&gt;if the hackers were out there&lt;/a&gt;, we'd be in big trouble.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/833174317742362874-6666768773740268340?l=insanecoding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://insanecoding.blogspot.com/feeds/6666768773740268340/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=833174317742362874&amp;postID=6666768773740268340' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/833174317742362874/posts/default/6666768773740268340'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/833174317742362874/posts/default/6666768773740268340'/><link rel='alternate' type='text/html' href='http://insanecoding.blogspot.com/2011/04/failure-of-fragmented-security.html' title='The failure of fragmented security'/><author><name>insane coder</name><uri>http://www.blogger.com/profile/06901386115570670209</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-833174317742362874.post-8474574769803680321</id><published>2010-11-25T14:51:00.001-08:00</published><updated>2010-11-26T02:34:24.177-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='good code'/><category scheme='http://www.blogger.com/atom/ns#' term='recursion'/><category scheme='http://www.blogger.com/atom/ns#' term='compatibility'/><category scheme='http://www.blogger.com/atom/ns#' term='Library'/><category scheme='http://www.blogger.com/atom/ns#' term='GCC'/><category scheme='http://www.blogger.com/atom/ns#' term='insane ideas'/><category scheme='http://www.blogger.com/atom/ns#' term='C++-201x'/><category scheme='http://www.blogger.com/atom/ns#' term='variadic templates'/><category scheme='http://www.blogger.com/atom/ns#' term='C++-0x'/><category scheme='http://www.blogger.com/atom/ns#' term='Portability'/><category scheme='http://www.blogger.com/atom/ns#' term='language'/><category scheme='http://www.blogger.com/atom/ns#' term='protocols'/><title type='text'>C++ Serialization Anyone?</title><content type='html'>Today I had one of the most amazing programming experiences that I've ever had, from my entire exciting career. I'm still a bit stunned that this happened. I fully thought what happened was completely impossible till now.&lt;br /&gt;&lt;br /&gt;At work, we use a lot of different languages to create our software. It's not odd for us to be working on a project which somehow ends up using a dozen languages. Between server code, client code, databases, communication, mark up, styling, pre-processing, dynamic code generation, and other commonality, it's rather easy actually.&lt;br /&gt;&lt;br /&gt;Between all these different programming languages, quite often, we need some sort of data interchange format. There's many to choose from, ranging from something custom to something well known like XML. Using these formats, we can pass data from one segment of our application stack to another. Even when they use two different programming languages. Or to save some data, and load it back up later.&lt;br /&gt;&lt;br /&gt;When it comes to these things, soft typed functional languages are generally easier to work with than hard typed. Soft typed languages are very good at building objects from data on the fly, thanks to their ability to not care much about what types they're looking at. Is it a number or a string? Doesn't matter to the soft typed language, as they store it all the same way.&lt;br /&gt;&lt;br /&gt;When dealing with database access from hard typed languages, the popular method is to create some sort of catch all or convert to &lt;i&gt;anything&lt;/i&gt; type. For some, terms like "QVariant" or "boost::any" are always on their lips. The intent of these and similar constructs is to ease things when dealing with data in an unknown type. Although such constructs generally require building a switch block which needs to check some enumeration method to figure out how to handle the data within the rest of the program. Such code is just downright annoying.&lt;br /&gt;&lt;br /&gt;At work some time back, thanks to a lot of the new features C++-201x has been adding, we've been able to build a database access library which can handle data without any of these old kludges. Essentially, database access for us in C++ is now just as easy as it is in PHP (or perhaps even easier!).&lt;br /&gt;&lt;br /&gt;Now database communication is great, but there's still the issue of data interchange between two programs, which aren't using a database as an intermediary. Many soft typed or functional languages can have a simple encode() or decode() function, pass it any object, and have a nice string representation of it which can be sent off, or saved to a file for later. C++ and related languages always had the nightmare of needing to iterate manually over every data type, or over a hierarchy to work with something like XML, or similar data formats.&lt;br /&gt;&lt;br /&gt;There's those that have created workarounds of course. Such as adding a serialize() function for every type you have to work with individually. Or create some serializable objects that one copies data to or from, and which handle all the serialization work internally. Or one of my personal favorites, write a separate parser which can read a description of a format, and generate the C++ objects and code needed to serialize or deserialize it.&lt;br /&gt;&lt;br /&gt;Well, today a coworker and I were putting our heads together on how to deal with a certain project. I wrote code some time back which can serialize/deserialize to and from an std::map which contains numbers, strings, or a mix thereof. We were using this data interchange format between two programs. However, now we need to deal with much more complex data, and a series of key pairs just won't cover it. One end of the equation is C++, the other end is a soft typed language which could pretty easily work with whatever we came up with.&lt;br /&gt;&lt;br /&gt;We first thought about the option of using a classic method such as XML or JSON, and use some kind of hierarchical writer from C++, and have the soft typed language just read it directly into an object with one of its built in language features. Till my friend had a brilliant realization. The hierarchy of language containers and their children is &lt;b&gt;recursive&lt;/b&gt;, as is any serialization that can encode an infinite amount of data stacked in a hierarchy. Then we started discussing if we could make a serialize() function in C++ which could take any C++ type and work, even when not knowing everything about it in advance. It'd be easy for plain old data types, but gets more complicated once we start dealing with containers of those, and containers of containers.&lt;br /&gt;&lt;br /&gt;Of course this is where most conversations along these lines end. But then I brought up template meta programming, and some new features C++ is now adding (and already in GCC), and this discussion went on much further than usual, till the point we were talking code. Well, we got into it, and two hours and two hundred lines of code later, we now have a function with the following prototype:&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;template&amp;lt;typename T&amp;gt;&lt;br /&gt;std::string serialize(const T &amp;amp;t);&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;It is able to take any type that exists in C++, and well, serialize it. Have some type which contains some types which contains a few more types which contains some other types? It's all serializeable with this function. No pre-processing, dynamic code generation, compiler hacks, or clumsy per program hierarchical parsing required. It just works&lt;sup&gt;TM&lt;/sup&gt;.&lt;br /&gt;&lt;br /&gt;Now next week, we'll have to write the deserializer function to pull that magic in reverse. Using the same idea, it shouldn't be a problem. If the data matches the supplied structure, parse it in, otherwise, throw an error. But currently, our project is done, as we are now able to have our C++ applications send very complex data to our soft typed languages rather easily.&lt;br /&gt;&lt;br /&gt;Looking over the code with my coworker, it all seems extremely obvious. Why the heck didn't we think of this 20 years ago? Now am I getting all excited over something that has been done before? Anyone familiar with anything like this?&lt;br /&gt;&lt;br /&gt;Question is, what to do now that we know this? File for a patent? (Yes, I'm evil!) Or perhaps ignore this, as no one cares about this topic anyway?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/833174317742362874-8474574769803680321?l=insanecoding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://insanecoding.blogspot.com/feeds/8474574769803680321/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=833174317742362874&amp;postID=8474574769803680321' title='14 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/833174317742362874/posts/default/8474574769803680321'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/833174317742362874/posts/default/8474574769803680321'/><link rel='alternate' type='text/html' href='http://insanecoding.blogspot.com/2010/11/c-serialization-anyone.html' title='C++ Serialization Anyone?'/><author><name>insane coder</name><uri>http://www.blogger.com/profile/06901386115570670209</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>14</thr:total></entry><entry><id>tag:blogger.com,1999:blog-833174317742362874.post-2620795255299236918</id><published>2010-10-30T16:29:00.000-07:00</published><updated>2010-10-31T00:58:09.510-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='crazy executives'/><category scheme='http://www.blogger.com/atom/ns#' term='Mozilla'/><category scheme='http://www.blogger.com/atom/ns#' term='distribution'/><category scheme='http://www.blogger.com/atom/ns#' term='Windows'/><category scheme='http://www.blogger.com/atom/ns#' term='competition'/><category scheme='http://www.blogger.com/atom/ns#' term='KDE'/><category scheme='http://www.blogger.com/atom/ns#' term='open source'/><category scheme='http://www.blogger.com/atom/ns#' term='compatibility'/><category scheme='http://www.blogger.com/atom/ns#' term='pure failure'/><category scheme='http://www.blogger.com/atom/ns#' term='HTTP'/><category scheme='http://www.blogger.com/atom/ns#' term='Google'/><category scheme='http://www.blogger.com/atom/ns#' term='standards compliance'/><category scheme='http://www.blogger.com/atom/ns#' term='Portability'/><title type='text'>This just in, 20% of enterprises and most IT people are idiots</title><content type='html'>So, who still runs Internet Explorer 6? I do, because sometimes, I'm a web developer.&lt;br /&gt;Along with IE 6, I also run later versions of IE, as well as Firefox, Opera, Chrome, Safari, Arora, Maxthon, and Konqueror. So do my web developer friends and coworkers.&lt;br /&gt;&lt;br /&gt;The reason why we do is simple. We want to test our products with every browser with any sort of popularity. Or is a browser that comes with some sort of OS or environment with any sort of popularity. Same goes for browsers with a specific engine.&lt;br /&gt;&lt;br /&gt;By playing with so many browsers, we get a feel for things which seem to not be well known (even when documented well), or completely missed by the "pros" who write the most noise on the subject at hand. After work, sometimes my coworkers and I like to get together and joke about how Google security researchers put out a security memo on IE, citing no recourse, while the solution is clearly documented on MSDN, or any similar scenario.&lt;br /&gt;&lt;br /&gt;Perhaps we're bad guys for not writing lengthy articles on every subject, and keeping knowledge to ourselves. On the other hand, we get to laugh at the general population on a regular basis. Something which I'm sure every geek at heart revels in.&lt;br /&gt;&lt;br /&gt;Here's a small sampling of popular beliefs that we snicker at:&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;Internet Explorer 6 can't &lt;a href="http://groopex.com/"&gt;properly display transparent PNGs&lt;/a&gt; without resorting to fancy CSS+JS hacks.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;JavaScript event handling code can't receive the event handle with IE.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Menus are required to be written in JavaScript to work with all browsers.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;IE is unable to &lt;a href="http://msdn.microsoft.com/en-us/library/aa384321%28v=VS.85%29.aspx"&gt;receive multiple cookies in a single Set-Cookie field&lt;/a&gt;.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Cookies is the (only) proper way to store HTTP state.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;IE is not the most advanced browser when it comes to text and typography (&lt;a href="http://www.microsoft.com/middleeast/msdn/JustifyingText-CSS.aspx"&gt;because it is, by far&lt;/a&gt;).&lt;/li&gt;&lt;br /&gt;&lt;li&gt;SSL/TLS can never be &lt;a href="http://en.wikipedia.org/wiki/Server_Name_Indication"&gt;used with multiple virtual hosts&lt;/a&gt;.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Common examples of how to write proper cross browser code is accurate. (Such as common methods to support embedded fonts for IE and other browsers break Konqueror, when supporting all of them is a piece of cake. Or use embed tags for &lt;a href="http://tasvideos.org/"&gt;flash&lt;/a&gt;.)&lt;/li&gt;&lt;br /&gt;&lt;li&gt;HTTP doesn't have &lt;a href="http://tools.ietf.org/html/rfc2617"&gt;native authentication abilities&lt;/a&gt;.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;a href="http://developer.yahoo.com/performance/rules.html#js_bottom"&gt;JavaScript should be included in&lt;/a&gt; HTML head.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;a href="http://www.php.net/manual/en/class.pdostatement.php"&gt;SQL query parameters&lt;/a&gt; should be escaped.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Faith in standards committees, large corporations, open source projects, or security researchers.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;That multiple versions of IE can't be run on Windows easily, especially older versions of IE on newer versions of Windows.&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;That last one is actually what prompted this article. &lt;a href="http://www.computerworld.com/s/article/9193901/IE6_addiction_throws_monkey_wrench_into_Windows_7_migration"&gt;20% of enterprises say they can't upgrade to newer versions of Windows because they need to use IE 6&lt;/a&gt;. On top of this, almost every IT guy who had anything to say about this believe in this situation or mentions virtualization as an out. Heck, even Microsoft themselves are saying you need a special XP mode in Windows 7 for IE 6, as is every major article site on the net who comment on this situation.&lt;br /&gt;&lt;br /&gt;Hilarious considering that you can &lt;a href="http://utilu.com/IECollection/#table"&gt;install and run IE 6 just fine in Windows 7&lt;/a&gt;. There's plenty of solutions out there besides that one too. They've also been around for several years.&lt;br /&gt;&lt;br /&gt;Anyways, experts, pros, designers, IT staff and average Internet surfers out there, just keep on being clueless on every single topic, some of us are having a real laugh.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/833174317742362874-2620795255299236918?l=insanecoding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://insanecoding.blogspot.com/feeds/2620795255299236918/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=833174317742362874&amp;postID=2620795255299236918' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/833174317742362874/posts/default/2620795255299236918'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/833174317742362874/posts/default/2620795255299236918'/><link rel='alternate' type='text/html' href='http://insanecoding.blogspot.com/2010/10/this-just-in-20-of-enterprises-and-most.html' title='This just in, 20% of enterprises and most IT people are idiots'/><author><name>insane coder</name><uri>http://www.blogger.com/profile/06901386115570670209</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-833174317742362874.post-6394991886782955885</id><published>2010-10-24T06:12:00.000-07:00</published><updated>2010-10-24T06:52:03.402-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='competition'/><category scheme='http://www.blogger.com/atom/ns#' term='parameters'/><category scheme='http://www.blogger.com/atom/ns#' term='CPU Detection'/><category scheme='http://www.blogger.com/atom/ns#' term='compatibility'/><category scheme='http://www.blogger.com/atom/ns#' term='BIOS'/><category scheme='http://www.blogger.com/atom/ns#' term='API'/><category scheme='http://www.blogger.com/atom/ns#' term='binary'/><category scheme='http://www.blogger.com/atom/ns#' term='protocols'/><category scheme='http://www.blogger.com/atom/ns#' term='closed source'/><title type='text'>Programming manuals for those who "get it"</title><content type='html'>Top secret official programming manuals for certain popular hand held devices have now been uploaded to the &lt;span style="font-style:italic;"&gt;usual&lt;/span&gt; &lt;span style="font-weight:bold;"&gt;public&lt;/span&gt; document repositories. Some have been around for a while to those who &lt;span style="font-style:italic;"&gt;get it&lt;/span&gt;, some are new.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/833174317742362874-6394991886782955885?l=insanecoding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://insanecoding.blogspot.com/feeds/6394991886782955885/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=833174317742362874&amp;postID=6394991886782955885' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/833174317742362874/posts/default/6394991886782955885'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/833174317742362874/posts/default/6394991886782955885'/><link rel='alternate' type='text/html' href='http://insanecoding.blogspot.com/2010/10/programming-manuals-for-those-who-get.html' title='Programming manuals for those who &quot;get it&quot;'/><author><name>insane coder</name><uri>http://www.blogger.com/profile/06901386115570670209</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-833174317742362874.post-8756036999901138643</id><published>2010-09-19T04:59:00.000-07:00</published><updated>2010-09-19T08:03:16.186-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Library'/><category scheme='http://www.blogger.com/atom/ns#' term='opendir'/><category scheme='http://www.blogger.com/atom/ns#' term='bad code'/><category scheme='http://www.blogger.com/atom/ns#' term='readdir'/><category scheme='http://www.blogger.com/atom/ns#' term='file descriptor'/><category scheme='http://www.blogger.com/atom/ns#' term='open source'/><category scheme='http://www.blogger.com/atom/ns#' term='good code'/><category scheme='http://www.blogger.com/atom/ns#' term='fstatat'/><category scheme='http://www.blogger.com/atom/ns#' term='torture'/><category scheme='http://www.blogger.com/atom/ns#' term='directory'/><category scheme='http://www.blogger.com/atom/ns#' term='searching'/><category scheme='http://www.blogger.com/atom/ns#' term='sorting'/><category scheme='http://www.blogger.com/atom/ns#' term='language'/><category scheme='http://www.blogger.com/atom/ns#' term='Hashing'/><category scheme='http://www.blogger.com/atom/ns#' term='Optimization'/><title type='text'>Optimizing your file dialog</title><content type='html'>Recently, someone asked me why is it that the custom file dialogs in some programs I wrote are able to load a file list so much faster than the so called "native file dialogs" on those operating systems. The answer is that I optimized many areas of loading a file list, and displaying it. Today we'll look at some optimizations that can be performed, instead of using the most obvious approaches to most of the process.&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;br /&gt;&lt;li&gt;&lt;h4&gt;Know your system calls for reading directory entries&lt;/h4&gt;&lt;br /&gt;&lt;br /&gt;You'll want to create some sort of library around the native directory functions in order to use the most efficient path on each operating system. Operating systems vary widely in what they they provide.&lt;br /&gt;&lt;br /&gt;Sometimes you have multiple APIs, or a single API with many options you can turn on and off. Unless the provided API is in itself doing everything as efficiently as possible (such as efficiently returning the file names in a sorted matter), you'll want to use the lowest level API, or turn off all options it provides.&lt;br /&gt;&lt;br /&gt;If bidirectional or scanning options are provided, turn them off, as you'll want forward only. The overhead for some of these features can significantly slow down the process of obtaining a file list. Same goes for anything else that adds overhead.&lt;br /&gt;&lt;br /&gt;Be aware of what information is provided other than file names. Some OSs will return a structure which may also contain file size or file permissions alongside each file. If you're filtering by any of these, use the information directly there, instead of using an additional call to stat() or similar.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;In addition to the above, if you need to filter by file size or file permissions, and the API does not provide that information directly, avoid the need for concatenating strings to get your information. A call to stat() would require concatenating a file name onto the directory name if it's not in the current directory. If your OS provides for it, use fstatat() or similar instead (see "OpenGroup Extended API Set Part 2").&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;h4&gt;Process file names in an optimized manner&lt;/h4&gt;&lt;br /&gt;Once you start getting back file name(s), before anything, determine the length of a file name, as all other operations will need to know the length. Pretty much every operating system / file system limits the length of a file name to 255 bytes, the length of that can fit in a single byte. Compute the length (if need be) and keep reusing this cache.&lt;br /&gt;&lt;br /&gt;If you want to do extension filtering, now is the time to do so. Do not use strrchr(),  or anything of the sort to find where the extension begins (searching for a period). Functions like strrchr() will first travel to the end then look back, effectively being O(2N). Since you already know the length of the string, use an O(N) function to look back from the end. Perhaps even using one which can scan multiple bytes (whole CPU words) at a time.&lt;br /&gt;&lt;br /&gt;For extension filtering, the most common method is generally one that breaks down to a series of compares. Put a little more thought into your algorithm usage! Either sort your list of extensions and &lt;a href="http://en.wikipedia.org/wiki/Binary_search_algorithm"&gt;binary search&lt;/a&gt; it for a match, or use &lt;a href="http://en.wikipedia.org/wiki/Perfect_hash_function"&gt;perfect hashing&lt;/a&gt;. In either case, make sure the sorting or hashing phase is performed just once.&lt;br /&gt;&lt;br /&gt;For copying the files names you want elsewhere, use memcpy() instead of strcpy() and similar. Don't forget to pass around the length for other uses too.&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;br /&gt;&lt;li&gt;&lt;h4&gt;Use efficient data structures efficiently&lt;/h4&gt;&lt;br /&gt;The next question is how to keep track of your list of files. The most two common ideas are to use a vector and just keep adding to it, or use a linked list. Both those solutions are wrong.&lt;br /&gt;&lt;br /&gt;A vector while great in theory, has some performance and memory issues. When a vector can no longer contain what is being added to it, it doubles in size. The doubling in size can cause up to 99% more allocation than is actually needed during the growing process, which also comes with a lot of copying around. This may suit many workloads, but won't always suit the file list workload well.&lt;br /&gt;&lt;br /&gt;A linked list on the other hand is one of the worst possible data structures you can use. Every entry has 100-200% extra overhead for pointers, and often means many series of allocations. Many small allocations leads to performance issues, and a lot of memory fragmentation.&lt;br /&gt;&lt;br /&gt;The solution I would recommend is either a tweaked vector, or a combination of a vector plus linked list. Tweaking a vector starts off with reserving a set amount of space up front. Have your vector by default start with room for say 512 entries, and only then grow as needed. When you see your vector is full, instead of doubling in size, reserve another 512 entries. Smaller requests are more likely to be fulfilled for a realloc() in the same location, than a doubling in size. Very large directories beyond this point also becomes increasingly rarer at each new milestone. On top of all this, have your program remember how many files were in each of the past 10 or so directories it looked in (with filtering options of course). Then when loading a directory you recently loaded in the past, you can allocate an amount which is usually just what you need, or only needs one more chunk allocated onto it. Keep in mind that most users will keep using the same few directories over and over again with each application.&lt;br /&gt;&lt;br /&gt;The combination of the vector and linked list would instead build a structure out of the two ideas combined. Create your array of 512 entries, along with a fill pointer and and linked list pointers. When your array is full, allocate another block of this structure as the next chain in the linked list. This ensures no need to ever reallocate, or copy data around during the growing phase. Of course keep a global pointer to the current link being filled, instead of iterating to it each time you add a new entry.&lt;br /&gt;&lt;br /&gt;Which of these two options you use depends on how you want to sort and display your files. Each data structure has pros and cons for different use cases. Before we get into that, know how to store your file names themselves.&lt;br /&gt;&lt;br /&gt;The above description was for the pointers to the arrays holding the file names, the file names should NOT have a separate block of allocated memory for each. That's inefficient. Instead allocate large chunks of memory, say 16KB each. Store your file names in this &lt;a href="http://en.wikipedia.org/wiki/Memory_pool"&gt;memory pool&lt;/a&gt;. Forget the silly trailing null if you can, store the length before the name itself. The two data structures explained above for containing lists of files will point into these pools. If a pool can't contain another entry you're about to add, allocate another 16KB chunk, point to it from the previous one, and start allocating in this new one. If the need for a new one was for a rare overly large file, say 230 bytes, when 200 bytes were free, you can implement an algorithm to save some overhead by seeing if the next couple of files fit into the end of any previous pools. The pools in general will probably waste less than your OSs malloc() for small file names, and you'll certainly get better performance. Deallocation will also be a quick (backwards) traversal for large chunks instead of many small ones.&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;h4&gt;Sort efficiently&lt;/h4&gt;&lt;br /&gt;The first part of sorting is comparison. strcmp()/strncmp() is not the function to use. You want something based on memcmp() as that works faster thanks to having the length of the file name already cached. Of course that's only if you want standard sorting.&lt;br /&gt;&lt;br /&gt;If you want case insensitive sorting, other methods will have to be used. If you're only dealing with ASCII file names, and you're not worried about file names containing control characters or some symbols end up being of equal value, you can compare 4 bytes at a time or'ing each with 0x20202020 (0x2020202020202020 for 8 bytes at a time). You're probably out of luck otherwise for case insensitive, unless someone knows of any good tricks to use.&lt;br /&gt;&lt;br /&gt;If you need "natural sorting", where numbers are compared to each other, so file1 precedes file15, and file2 follows file1 not file15, there's a few implementations floating around online and most are just copies of one another. Sadly, the most popular one I see, which is present in two operating systems, and the native implementation in a particular programming language, happens to incorrectly handle numbers past a certain magnitude (did anyone even test the implementations or just accept them at face value?), and has a worse case of O(3N). So beware of what you use or base your code off of.&lt;br /&gt;&lt;br /&gt;I'd recommend something along these lines:&lt;br /&gt;&lt;pre style="background-color:#F5F2D5;"&gt;&lt;br /&gt;&lt;span style="color: #800000;"&gt;int&lt;/span&gt;&lt;span style="color: #000000;"&gt; strnatbase(&lt;/span&gt;&lt;span style="color: #800000;"&gt;const&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #800000;"&gt;char&lt;/span&gt;&lt;span style="color: #000000;"&gt; *s1, &lt;/span&gt;&lt;span style="color: #800000;"&gt;const&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #800000;"&gt;char&lt;/span&gt;&lt;span style="color: #000000;"&gt; *s2)&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;{&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;for&lt;/span&gt;&lt;span style="color: #000000;"&gt; (; *s1; ++s1, ++s2) &lt;/span&gt;&lt;span style="font-style: italic;color: #808080;"&gt;//No need to check s2, as we compare it to s1, and it won't equal if it's null&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  {&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;    &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;if&lt;/span&gt;&lt;span style="color: #000000;"&gt; (isdigit(*s1) &amp;amp;&amp;amp; isdigit(*s2)) &lt;/span&gt;&lt;span style="font-style: italic;color: #808080;"&gt;//If they're both digits, use this special handling&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;    {&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;      &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;while&lt;/span&gt;&lt;span style="color: #000000;"&gt; (*s1 == &lt;/span&gt;&lt;span style="color: #ff00ff;"&gt;'0'&lt;/span&gt;&lt;span style="color: #000000;"&gt;) { ++s1; } &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;while&lt;/span&gt;&lt;span style="color: #000000;"&gt; (*s2 == &lt;/span&gt;&lt;span style="color: #ff00ff;"&gt;'0'&lt;/span&gt;&lt;span style="color: #000000;"&gt;) { ++s2; } &lt;/span&gt;&lt;span style="font-style: italic;color: #808080;"&gt;//First skip leading zeros&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;      &lt;/span&gt;&lt;span style="color: #800000;"&gt;register&lt;/span&gt;&lt;span style="color: #000000;"&gt; bool d1 = isdigit(*s1), d2 = isdigit(*s2); &lt;/span&gt;&lt;span style="font-style: italic;color: #808080;"&gt;//Are we still in a run of digits for both strings?&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;      &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;if&lt;/span&gt;&lt;span style="color: #000000;"&gt; (d1 != d2) { &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;return&lt;/span&gt;&lt;span style="color: #000000;"&gt;(d1-d2); } &lt;/span&gt;&lt;span style="font-style: italic;color: #808080;"&gt;//If for only one of them, return that as the difference&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;      &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;for&lt;/span&gt;&lt;span style="color: #000000;"&gt; (; d1 &amp;amp;&amp;amp; (*s1 == *s2); ++s2) { d1 = isdigit(*++s1); } &lt;/span&gt;&lt;span style="font-style: italic;color: #808080;"&gt;//Keep going while we have matching digits&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;      d2 = isdigit(*s2); &lt;/span&gt;&lt;span style="font-style: italic;color: #808080;"&gt;//If we broke the above loop because a single string ran out of digits&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;      &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;if&lt;/span&gt;&lt;span style="color: #000000;"&gt; (d1 != d2) { &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;return&lt;/span&gt;&lt;span style="color: #000000;"&gt;(d1-d2); } &lt;/span&gt;&lt;span style="font-style: italic;color: #808080;"&gt;//Return that as the difference&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;      &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;for&lt;/span&gt;&lt;span style="color: #000000;"&gt; (&lt;/span&gt;&lt;span style="color: #800000;"&gt;const&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #800000;"&gt;char&lt;/span&gt;&lt;span style="color: #000000;"&gt; *p1 = s1, *p2 = s2; d1; ) &lt;/span&gt;&lt;span style="font-style: italic;color: #808080;"&gt;//Otherwise, difference in the digits themselves, clarify magnitude&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;      {&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;        d1 = isdigit(*++p1); d2 = isdigit(*++p2); &lt;/span&gt;&lt;span style="font-style: italic;color: #808080;"&gt;//First string to run out of digits first&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;        &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;if&lt;/span&gt;&lt;span style="color: #000000;"&gt; (d1 != d2) { &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;return&lt;/span&gt;&lt;span style="color: #000000;"&gt;(d1-d2); } &lt;/span&gt;&lt;span style="font-style: italic;color: #808080;"&gt;//Will lose right here&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;      } &lt;/span&gt;&lt;span style="font-style: italic;color: #808080;"&gt;//If loop breaks, both strings are out of digits, the difference found above will be handled below&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;    }&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;   &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;if&lt;/span&gt;&lt;span style="color: #000000;"&gt; (NOT_EQUAL(*s1, *s2)) { &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;break&lt;/span&gt;&lt;span style="color: #000000;"&gt;; } &lt;/span&gt;&lt;span style="font-style: italic;color: #808080;"&gt;//In all other cases, fall through with difference in current position - if any&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  }&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;return&lt;/span&gt;&lt;span style="color: #000000;"&gt;(*s1-*s2);&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Modify as necessary for unicode, and replace NOT_EQUAL() with your function (or macro) of choice for comparing two letters (accounting for case differences if you want).&lt;br /&gt;&lt;br /&gt;As for the sort functions themselves, it will depend on which data structure you chose. You'll probably want &lt;a href="http://en.wikipedia.org/wiki/Quicksort"&gt;Quicksort&lt;/a&gt; for the vector. Make sure your Quicksort sorts the pointers to the data and not the data itself! Same for any sorting algorithm sorting this. Swapping pointers is quick and easy. For the latter structure, you might want &lt;a href="http://en.wikipedia.org/wiki/Merge_sort"&gt;Merge sort&lt;/a&gt;, or perhaps &lt;a href="http://en.wikipedia.org/wiki/Smoothsort"&gt;Smoothsort&lt;/a&gt;. What you choose can depend on several factors.&lt;br /&gt;&lt;br /&gt;You may or may not want to utilize threading. Depending on how you filter, the OS may be giving you mostly sorted file names which can also play a role in the algorithm you choose. In the case of the linked lists of arrays, you might want to sort each array with one algorithm, then sort the whole. If you're utilizing threading, you can begin sorting the array(s) as you're still obtaining files from the operating system, as disk reads are slower than memory reads (when the current directory contents is not (yet) cached by the OS).&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;h4&gt;Display directly&lt;/h4&gt;&lt;br /&gt;This point is rather simple. Have your file dialog display entries directly from whichever data structure you chose, without copying anything around. Know that most existing file dialog routines provided by various libraries will not be compatible with the data structures described above. So roll your own, or choose structures which can be passed directly to your library.&lt;br /&gt;&lt;br /&gt;Another possibility is to copy entries as they fit in the dialog window. The dialog is unable to show an infinite amount of entries at once, so convert from your structure to its structure just for the current files being viewed. Update as scrolling is performed.&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;h4&gt;Search efficiently&lt;/h4&gt;&lt;br /&gt;Many file dialogs provide the option to type in some characters, and the file dialog jumps to the first file that begins with those characters. Since your file dialog is sorted, use binary search. Some people don't realize this, but binary search can find more than just an exact match, binary search can also be used to find the transition from entries "less than" to "first equal match" (in other words, binary search can also be used to find the transition between entries before the first match and the first match itself). Use this to find the first matching file in O(log(N)).&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;&lt;br /&gt;This basically wraps up this discussion on how to optimize file dialogs. I once was annoyed that loading up a directory with 20,000 files in it on a particular OS with a particular file browser took a good torturesome 20-30 seconds. Now using my own, I can load a directory with 100,000 files in 1-2 seconds on the same setup.&lt;br /&gt;&lt;br /&gt;Thoughts, improvements, complaints, and every other kind of comment is welcome. Be sure to comment if you take of these ideas to optimize your library or application. I'd love to hear about it.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/833174317742362874-8756036999901138643?l=insanecoding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://insanecoding.blogspot.com/feeds/8756036999901138643/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=833174317742362874&amp;postID=8756036999901138643' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/833174317742362874/posts/default/8756036999901138643'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/833174317742362874/posts/default/8756036999901138643'/><link rel='alternate' type='text/html' href='http://insanecoding.blogspot.com/2010/09/optimizing-your-file-dialog.html' title='Optimizing your file dialog'/><author><name>insane coder</name><uri>http://www.blogger.com/profile/06901386115570670209</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-833174317742362874.post-4792719090417915905</id><published>2010-07-24T10:53:00.000-07:00</published><updated>2010-07-25T04:42:08.178-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='good code'/><category scheme='http://www.blogger.com/atom/ns#' term='parameters'/><category scheme='http://www.blogger.com/atom/ns#' term='types'/><category scheme='http://www.blogger.com/atom/ns#' term='Function Pointers'/><category scheme='http://www.blogger.com/atom/ns#' term='insane ideas'/><category scheme='http://www.blogger.com/atom/ns#' term='factory'/><category scheme='http://www.blogger.com/atom/ns#' term='Optimization'/><title type='text'>Simplifying bootstrapping for virtual constructors</title><content type='html'>Last week I &lt;a href="http://insanecoding.blogspot.com/2010/07/time-to-shutdown-factory-for-code.html"&gt;demonstrated a solution&lt;/a&gt; to the virtual constructor problem. My solution avoids many issues with the factory function solution. Yet it did require some bootstrapping to use.&lt;br /&gt;&lt;br /&gt;The bootstrapping required a new function to be created for every single derived class that needs to be virtualized. When working with many derived classes, this becomes unacceptable. It's bad enough to solve this problem we need to generate a map, should we have to create additional functions as well? Each time a new derived class is added, should I go out of my way with two steps?&lt;br /&gt;&lt;br /&gt;Turns out, making use of templates, we can combine the define and function generation step.&lt;br /&gt;&lt;pre style="background-color:#F5F2D5"&gt;&lt;br /&gt;&lt;span style="color: #800000;"&gt;static&lt;/span&gt;&lt;span style="color: #000000;"&gt; compress *compress_zip::construct() { &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;return&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;new&lt;/span&gt;&lt;span style="color: #000000;"&gt; compress_zip; }&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #800000;"&gt;static&lt;/span&gt;&lt;span style="color: #000000;"&gt; compress *compress_gzip::construct() { &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;return&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;new&lt;/span&gt;&lt;span style="color: #000000;"&gt; compress_gzip; }&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #800000;"&gt;static&lt;/span&gt;&lt;span style="color: #000000;"&gt; compress *compress_7zip::construct() { &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;return&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;new&lt;/span&gt;&lt;span style="color: #000000;"&gt; compress_7zip; }&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Instead of creating the above, and using it as follows:&lt;br /&gt;&lt;pre style="background-color:#F5F2D5"&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;std::map&amp;lt;COMPRESS_TYPES, compress *(*)()&amp;gt; compress_factory;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;compress_factory[COMPRESS_ZIP] = compress_zip::construct;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;compress_factory[COMPRESS_GZIP] = compress_gzip::construct;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;compress_factory[COMPRESS_7ZIP] = compress_7zip::construct;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;First create a single construct template function:&lt;br /&gt;&lt;pre style="background-color:#F5F2D5"&gt;&lt;br /&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;template&lt;/span&gt;&lt;span style="color: #000000;"&gt; &amp;lt;&lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;typename&lt;/span&gt;&lt;span style="color: #000000;"&gt; T&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;compress *compress_construct()&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;{&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;return&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;new&lt;/span&gt;&lt;span style="color: #000000;"&gt; T;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;This has to be done only once.&lt;br /&gt;&lt;br /&gt;Now when adding to the map, we can do the following:&lt;br /&gt;&lt;pre style="background-color:#F5F2D5"&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;std::map&amp;lt;COMPRESS_TYPES, compress *(*)()&amp;gt; compress_factory;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;compress_factory[COMPRESS_ZIP] = compress_construct&amp;lt;compress_zip&amp;gt;;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;compress_factory[COMPRESS_GZIP] = compress_construct&amp;lt;compress_gzip&amp;gt;;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;compress_factory[COMPRESS_7ZIP] = compress_construct&amp;lt;compress_7zip&amp;gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;If some new type now comes along, simply add it with a single line. A new function will be generated on use by the template, so you no longer have to. Now we have truly managed to map a type directly to an identifier.&lt;br /&gt;&lt;br /&gt;Of course no tutorial would be complete without a self contained example:&lt;br /&gt;&lt;pre style="background-color:#F5F2D5"&gt;&lt;br /&gt;&lt;span style="color: #008000;"&gt;#include &amp;lt;iostream&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #008000;"&gt;#include &amp;lt;map&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #008000;"&gt;#include &amp;lt;string&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;class&lt;/span&gt;&lt;span style="color: #000000;"&gt; base&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;{&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  std::string n;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;protected&lt;/span&gt;&lt;span style="color: #000000;"&gt;:&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  base(&lt;/span&gt;&lt;span style="color: #800000;"&gt;const&lt;/span&gt;&lt;span style="color: #000000;"&gt; std::string &amp;amp;n) : n(n) {}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;public&lt;/span&gt;&lt;span style="color: #000000;"&gt;:&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  base() : n(&lt;/span&gt;&lt;span style="color: #dd0000;"&gt;"base"&lt;/span&gt;&lt;span style="color: #000000;"&gt;) {}&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  std::string name() { &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;return&lt;/span&gt;&lt;span style="color: #000000;"&gt;(n); }&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;};&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;struct&lt;/span&gt;&lt;span style="color: #000000;"&gt; derived : &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;public&lt;/span&gt;&lt;span style="color: #000000;"&gt; base&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;{&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  derived() : base(&lt;/span&gt;&lt;span style="color: #dd0000;"&gt;"derived"&lt;/span&gt;&lt;span style="color: #000000;"&gt;) {}&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;};&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;template&lt;/span&gt;&lt;span style="color: #000000;"&gt; &amp;lt;&lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;typename&lt;/span&gt;&lt;span style="color: #000000;"&gt; T&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;base *construct()&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;{&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;return&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;new&lt;/span&gt;&lt;span style="color: #000000;"&gt; T;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #800000;"&gt;int&lt;/span&gt;&lt;span style="color: #000000;"&gt; main(&lt;/span&gt;&lt;span style="color: #800000;"&gt;int&lt;/span&gt;&lt;span style="color: #000000;"&gt; argc, &lt;/span&gt;&lt;span style="color: #800000;"&gt;const&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #800000;"&gt;char&lt;/span&gt;&lt;span style="color: #000000;"&gt; *&lt;/span&gt;&lt;span style="color: #800000;"&gt;const&lt;/span&gt;&lt;span style="color: #000000;"&gt; *&lt;/span&gt;&lt;span style="color: #800000;"&gt;const&lt;/span&gt;&lt;span style="color: #000000;"&gt; argv)&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;{&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  std::map&amp;lt;std::string, base *(*)()&amp;gt; factory;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  factory[&lt;/span&gt;&lt;span style="color: #dd0000;"&gt;"b"&lt;/span&gt;&lt;span style="color: #000000;"&gt;] = construct&amp;lt;base&amp;gt;;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  factory[&lt;/span&gt;&lt;span style="color: #dd0000;"&gt;"d"&lt;/span&gt;&lt;span style="color: #000000;"&gt;] = construct&amp;lt;derived&amp;gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;try&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  {&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;    &lt;/span&gt;&lt;span style="font-style: italic;color: #808080;"&gt;//Instantiate based on run-time variables&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;    base *obj = factory.at(argv[&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;1&lt;/span&gt;&lt;span style="color: #000000;"&gt;])();&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;    &lt;/span&gt;&lt;span style="font-style: italic;color: #808080;"&gt;//Output&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;    std::cout &amp;lt;&amp;lt; obj-&amp;gt;name() &amp;lt;&amp;lt; std::endl;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;    &lt;/span&gt;&lt;span style="font-style: italic;color: #808080;"&gt;//Cleanup&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;    &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;delete&lt;/span&gt;&lt;span style="color: #000000;"&gt; obj;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  }&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;catch&lt;/span&gt;&lt;span style="color: #000000;"&gt; (&lt;/span&gt;&lt;span style="color: #800000;"&gt;const&lt;/span&gt;&lt;span style="color: #000000;"&gt; std::exception &amp;amp;e) { std::cout &amp;lt;&amp;lt; &lt;/span&gt;&lt;span style="color: #dd0000;"&gt;"Error occured: "&lt;/span&gt;&lt;span style="color: #000000;"&gt; &amp;lt;&amp;lt; e.what() &amp;lt;&amp;lt; std::endl; }&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;return&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000ff;"&gt;0&lt;/span&gt;&lt;span style="color: #000000;"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Output:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;/tmp&amp;gt; g++-4.4 -Wall -o factory_test factory_test.cpp&lt;br /&gt;/tmp&amp;gt; ./factory_test b&lt;br /&gt;base&lt;br /&gt;/tmp&amp;gt; ./factory_test d&lt;br /&gt;derived&lt;br /&gt;/tmp&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Now that this problem has been solved nice and neatly. What about solving it for multiple constructors? Also known as the &lt;a href="http://en.wikipedia.org/wiki/Abstract_factory_pattern"&gt;abstract factory&lt;/a&gt; problem. What if each class has multiple constructors, and we want a collection of them mapped to a single identifier? Can we do it without repeating a lot of code over and over?&lt;br /&gt;&lt;br /&gt;With some minor bootstrapping, the answer is again yes! There's multiple solutions to this problem, but the following is what I found to be the nicest at the moment.&lt;br /&gt;&lt;br /&gt;First create a pure virtual class with a function to match each constructor you'd like to virtualize. Each should of course return a base pointer.&lt;br /&gt;&lt;br /&gt;Imagine we had 3 constructors, one taking no parameters, one taking a C string, and another taking a C++ string, we would setup the following:&lt;br /&gt;&lt;pre style="background-color:#F5F2D5"&gt;&lt;br /&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;struct&lt;/span&gt;&lt;span style="color: #000000;"&gt; construct_interface&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;{&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;virtual&lt;/span&gt;&lt;span style="color: #000000;"&gt; base *&lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;operator&lt;/span&gt;&lt;span style="color: #000000;"&gt;()() &lt;/span&gt;&lt;span style="color: #800000;"&gt;const&lt;/span&gt;&lt;span style="color: #000000;"&gt; = &lt;/span&gt;&lt;span style="color: #0000ff;"&gt;0&lt;/span&gt;&lt;span style="color: #000000;"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;virtual&lt;/span&gt;&lt;span style="color: #000000;"&gt; base *&lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;operator&lt;/span&gt;&lt;span style="color: #000000;"&gt;()(&lt;/span&gt;&lt;span style="color: #800000;"&gt;const&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #800000;"&gt;char&lt;/span&gt;&lt;span style="color: #000000;"&gt; *) &lt;/span&gt;&lt;span style="color: #800000;"&gt;const&lt;/span&gt;&lt;span style="color: #000000;"&gt; = &lt;/span&gt;&lt;span style="color: #0000ff;"&gt;0&lt;/span&gt;&lt;span style="color: #000000;"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;virtual&lt;/span&gt;&lt;span style="color: #000000;"&gt; base *&lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;operator&lt;/span&gt;&lt;span style="color: #000000;"&gt;()(&lt;/span&gt;&lt;span style="color: #800000;"&gt;const&lt;/span&gt;&lt;span style="color: #000000;"&gt; std::string &amp;amp;) &lt;/span&gt;&lt;span style="color: #800000;"&gt;const&lt;/span&gt;&lt;span style="color: #000000;"&gt; = &lt;/span&gt;&lt;span style="color: #0000ff;"&gt;0&lt;/span&gt;&lt;span style="color: #000000;"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;};&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Once we have the interface defined, we'll create a template construct function which implements and returns that interface within a singleton similar to the above construct function:&lt;br /&gt;&lt;pre style="background-color:#F5F2D5"&gt;&lt;br /&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;template&lt;/span&gt;&lt;span style="color: #000000;"&gt; &amp;lt;&lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;typename&lt;/span&gt;&lt;span style="color: #000000;"&gt; T&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #800000;"&gt;const&lt;/span&gt;&lt;span style="color: #000000;"&gt; construct_interface *construct()&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;{&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="color: #800000;"&gt;static&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;struct&lt;/span&gt;&lt;span style="color: #000000;"&gt; : &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;public&lt;/span&gt;&lt;span style="color: #000000;"&gt; construct_interface&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  {&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;    base *&lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;operator&lt;/span&gt;&lt;span style="color: #000000;"&gt;()() &lt;/span&gt;&lt;span style="color: #800000;"&gt;const&lt;/span&gt;&lt;span style="color: #000000;"&gt; { &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;return&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;new&lt;/span&gt;&lt;span style="color: #000000;"&gt; T; }&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;    base *&lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;operator&lt;/span&gt;&lt;span style="color: #000000;"&gt;()(&lt;/span&gt;&lt;span style="color: #800000;"&gt;const&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #800000;"&gt;char&lt;/span&gt;&lt;span style="color: #000000;"&gt; *s) &lt;/span&gt;&lt;span style="color: #800000;"&gt;const&lt;/span&gt;&lt;span style="color: #000000;"&gt; { &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;return&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;new&lt;/span&gt;&lt;span style="color: #000000;"&gt; T(s); }&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;    base *&lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;operator&lt;/span&gt;&lt;span style="color: #000000;"&gt;()(&lt;/span&gt;&lt;span style="color: #800000;"&gt;const&lt;/span&gt;&lt;span style="color: #000000;"&gt; std::string &amp;amp;s) &lt;/span&gt;&lt;span style="color: #800000;"&gt;const&lt;/span&gt;&lt;span style="color: #000000;"&gt; { &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;return&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;new&lt;/span&gt;&lt;span style="color: #000000;"&gt; T(s); }&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  } local;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;return&lt;/span&gt;&lt;span style="color: #000000;"&gt; &amp;amp;local;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;It'd be nice to return a reference instead of a pointer, but dealing with references in std::map is kind of icky. We can use macros to cleanup any annoying pointer dereferencing issues that could arise.&lt;br /&gt;&lt;br /&gt;Now our construct function returns a pointer to an interface which can construct a derived type using any of its constructors. We'll use it with an std::map like so:&lt;br /&gt;&lt;pre style="background-color:#F5F2D5"&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;std::map&amp;lt;std::string, &lt;/span&gt;&lt;span style="color: #800000;"&gt;const&lt;/span&gt;&lt;span style="color: #000000;"&gt; construct_interface *&amp;gt; factory;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;factory[&lt;/span&gt;&lt;span style="color: #dd0000;"&gt;"base"&lt;/span&gt;&lt;span style="color: #000000;"&gt;] = construct&amp;lt;base&amp;gt;();&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;factory[&lt;/span&gt;&lt;span style="color: #dd0000;"&gt;"derived"&lt;/span&gt;&lt;span style="color: #000000;"&gt;] = construct&amp;lt;derived&amp;gt;();&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Notice the map no longer tracks function pointers, but pointers to the interface. Also, when assigning to the map, we're calling the construct function to obtain the pointer. We could modify the above example to track function pointers and leave out the (), and even make the construct function return a reference to an interface instead, but then we'd need to add an extra () when creating objects. While that too can be hidden by a macro, or just ignored, as an extra () still looks rather clean, it does add extra overhead, as it is likely you'll initialize your map just once, and use it to create many objects during the lifetime of the program.&lt;br /&gt;&lt;br /&gt;Now to use the map to create an object, the following has to be done:&lt;br /&gt;&lt;pre style="background-color:#F5F2D5"&gt;&lt;br /&gt;&lt;span style="font-style: italic;color: #808080;"&gt;//Use first constructor, the default constructor&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;base *obj1 = (*(factory).at(id))();&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;color: #808080;"&gt;//Use second constructor, the one taking a C string&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;base *obj2 = (*(factory).at(id))(s);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;It works nicely, but as I explained above that's rather ugly.&lt;br /&gt;&lt;br /&gt;This macro can help simplify things:&lt;br /&gt;&lt;pre style="background-color:#F5F2D5"&gt;&lt;br /&gt;&lt;span style="color: #008000;"&gt;#define VIRTUAL_NEW(factory, id) (*(factory).at((id)))&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;And unlike the interface class and template construction function which needs to be created for each set of classes making use of virtual constructors, the above macro can be reused for every virtual constructor collection that makes use of the above idiom.&lt;br /&gt;&lt;br /&gt;Using the macro, the code now looks as follows:&lt;br /&gt;&lt;pre style="background-color:#F5F2D5"&gt;&lt;br /&gt;&lt;span style="font-style: italic;color: #808080;"&gt;//Use first constructor, the default constructor&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;base *obj1 = VIRTUAL_NEW(factory, id)();&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;color: #808080;"&gt;//Use second constructor, the one taking a C string&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;base *obj2 = VIRTUAL_NEW(factory, id)(s);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;That's it, problem solved!&lt;br /&gt;&lt;br /&gt;Putting it all together, here's a working example:&lt;br /&gt;&lt;pre style="background-color:#F5F2D5"&gt;&lt;br /&gt;&lt;span style="color: #008000;"&gt;#include &amp;lt;iostream&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #008000;"&gt;#include &amp;lt;map&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #008000;"&gt;#include &amp;lt;string&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #008000;"&gt;#include &amp;lt;cstdlib&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;class&lt;/span&gt;&lt;span style="color: #000000;"&gt; base&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;{&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;protected&lt;/span&gt;&lt;span style="color: #000000;"&gt;:&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="color: #800000;"&gt;int&lt;/span&gt;&lt;span style="color: #000000;"&gt; x, y;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;public&lt;/span&gt;&lt;span style="color: #000000;"&gt;:&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  base() : x(&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;1&lt;/span&gt;&lt;span style="color: #000000;"&gt;), y(&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;2&lt;/span&gt;&lt;span style="color: #000000;"&gt;) {}&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  base(&lt;/span&gt;&lt;span style="color: #800000;"&gt;const&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #800000;"&gt;char&lt;/span&gt;&lt;span style="color: #000000;"&gt; *s) : x(std::atoi(s)), y(&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;3&lt;/span&gt;&lt;span style="color: #000000;"&gt;) {}&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  base(&lt;/span&gt;&lt;span style="color: #800000;"&gt;const&lt;/span&gt;&lt;span style="color: #000000;"&gt; std::string &amp;amp;s) : x(std::atoi(s.c_str())), y(&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;4&lt;/span&gt;&lt;span style="color: #000000;"&gt;) {}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;virtual&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #800000;"&gt;int&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;operator&lt;/span&gt;&lt;span style="color: #000000;"&gt;()() { &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;return&lt;/span&gt;&lt;span style="color: #000000;"&gt; x+y; }&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;};&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;class&lt;/span&gt;&lt;span style="color: #000000;"&gt; derived : &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;public&lt;/span&gt;&lt;span style="color: #000000;"&gt; base&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;{&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;public&lt;/span&gt;&lt;span style="color: #000000;"&gt;:&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  derived() {}&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  derived(&lt;/span&gt;&lt;span style="color: #800000;"&gt;const&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #800000;"&gt;char&lt;/span&gt;&lt;span style="color: #000000;"&gt; *s) : base(s) {}&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  derived(&lt;/span&gt;&lt;span style="color: #800000;"&gt;const&lt;/span&gt;&lt;span style="color: #000000;"&gt; std::string &amp;amp;s) : base(s) {}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;virtual&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #800000;"&gt;int&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;operator&lt;/span&gt;&lt;span style="color: #000000;"&gt;()() { &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;return&lt;/span&gt;&lt;span style="color: #000000;"&gt; x*y; }&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;};&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;struct&lt;/span&gt;&lt;span style="color: #000000;"&gt; construct_interface&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;{&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;virtual&lt;/span&gt;&lt;span style="color: #000000;"&gt; base *&lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;operator&lt;/span&gt;&lt;span style="color: #000000;"&gt;()() &lt;/span&gt;&lt;span style="color: #800000;"&gt;const&lt;/span&gt;&lt;span style="color: #000000;"&gt; = &lt;/span&gt;&lt;span style="color: #0000ff;"&gt;0&lt;/span&gt;&lt;span style="color: #000000;"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;virtual&lt;/span&gt;&lt;span style="color: #000000;"&gt; base *&lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;operator&lt;/span&gt;&lt;span style="color: #000000;"&gt;()(&lt;/span&gt;&lt;span style="color: #800000;"&gt;const&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #800000;"&gt;char&lt;/span&gt;&lt;span style="color: #000000;"&gt; *) &lt;/span&gt;&lt;span style="color: #800000;"&gt;const&lt;/span&gt;&lt;span style="color: #000000;"&gt; = &lt;/span&gt;&lt;span style="color: #0000ff;"&gt;0&lt;/span&gt;&lt;span style="color: #000000;"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;virtual&lt;/span&gt;&lt;span style="color: #000000;"&gt; base *&lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;operator&lt;/span&gt;&lt;span style="color: #000000;"&gt;()(&lt;/span&gt;&lt;span style="color: #800000;"&gt;const&lt;/span&gt;&lt;span style="color: #000000;"&gt; std::string &amp;amp;) &lt;/span&gt;&lt;span style="color: #800000;"&gt;const&lt;/span&gt;&lt;span style="color: #000000;"&gt; = &lt;/span&gt;&lt;span style="color: #0000ff;"&gt;0&lt;/span&gt;&lt;span style="color: #000000;"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;};&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;template&lt;/span&gt;&lt;span style="color: #000000;"&gt; &amp;lt;&lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;typename&lt;/span&gt;&lt;span style="color: #000000;"&gt; T&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #800000;"&gt;const&lt;/span&gt;&lt;span style="color: #000000;"&gt; construct_interface *construct()&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;{&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="color: #800000;"&gt;static&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;struct&lt;/span&gt;&lt;span style="color: #000000;"&gt; : &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;public&lt;/span&gt;&lt;span style="color: #000000;"&gt; construct_interface&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  {&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;    base *&lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;operator&lt;/span&gt;&lt;span style="color: #000000;"&gt;()() &lt;/span&gt;&lt;span style="color: #800000;"&gt;const&lt;/span&gt;&lt;span style="color: #000000;"&gt; { &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;return&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;new&lt;/span&gt;&lt;span style="color: #000000;"&gt; T; }&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;    base *&lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;operator&lt;/span&gt;&lt;span style="color: #000000;"&gt;()(&lt;/span&gt;&lt;span style="color: #800000;"&gt;const&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #800000;"&gt;char&lt;/span&gt;&lt;span style="color: #000000;"&gt; *s) &lt;/span&gt;&lt;span style="color: #800000;"&gt;const&lt;/span&gt;&lt;span style="color: #000000;"&gt; { &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;return&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;new&lt;/span&gt;&lt;span style="color: #000000;"&gt; T(s); }&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;    base *&lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;operator&lt;/span&gt;&lt;span style="color: #000000;"&gt;()(&lt;/span&gt;&lt;span style="color: #800000;"&gt;const&lt;/span&gt;&lt;span style="color: #000000;"&gt; std::string &amp;amp;s) &lt;/span&gt;&lt;span style="color: #800000;"&gt;const&lt;/span&gt;&lt;span style="color: #000000;"&gt; { &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;return&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;new&lt;/span&gt;&lt;span style="color: #000000;"&gt; T(s); }&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  } local;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;return&lt;/span&gt;&lt;span style="color: #000000;"&gt; &amp;amp;local;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #008000;"&gt;#define VIRTUAL_NEW(factory, id) (*(factory).at((id)))&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #800000;"&gt;int&lt;/span&gt;&lt;span style="color: #000000;"&gt; main(&lt;/span&gt;&lt;span style="color: #800000;"&gt;int&lt;/span&gt;&lt;span style="color: #000000;"&gt; argc, &lt;/span&gt;&lt;span style="color: #800000;"&gt;const&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #800000;"&gt;char&lt;/span&gt;&lt;span style="color: #000000;"&gt; *&lt;/span&gt;&lt;span style="color: #800000;"&gt;const&lt;/span&gt;&lt;span style="color: #000000;"&gt; *&lt;/span&gt;&lt;span style="color: #800000;"&gt;const&lt;/span&gt;&lt;span style="color: #000000;"&gt; argv)&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;{&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  std::map&amp;lt;std::string, &lt;/span&gt;&lt;span style="color: #800000;"&gt;const&lt;/span&gt;&lt;span style="color: #000000;"&gt; construct_interface *&amp;gt; factory;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  factory[&lt;/span&gt;&lt;span style="color: #dd0000;"&gt;"b"&lt;/span&gt;&lt;span style="color: #000000;"&gt;] = construct&amp;lt;base&amp;gt;();&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  factory[&lt;/span&gt;&lt;span style="color: #dd0000;"&gt;"d"&lt;/span&gt;&lt;span style="color: #000000;"&gt;] = construct&amp;lt;derived&amp;gt;();&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;if&lt;/span&gt;&lt;span style="color: #000000;"&gt; (argc == &lt;/span&gt;&lt;span style="color: #0000ff;"&gt;3&lt;/span&gt;&lt;span style="color: #000000;"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  {&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;    &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;try&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;    {&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;      &lt;/span&gt;&lt;span style="font-style: italic;color: #808080;"&gt;//Instantiate based on run-time variables&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;      base *obj1 = VIRTUAL_NEW(factory, argv[&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;1&lt;/span&gt;&lt;span style="color: #000000;"&gt;])();&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;      base *obj2 = VIRTUAL_NEW(factory, argv[&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;1&lt;/span&gt;&lt;span style="color: #000000;"&gt;])(argv[&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;2&lt;/span&gt;&lt;span style="color: #000000;"&gt;]);&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;      base *obj3 = VIRTUAL_NEW(factory, argv[&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;1&lt;/span&gt;&lt;span style="color: #000000;"&gt;])(std::string(argv[&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;2&lt;/span&gt;&lt;span style="color: #000000;"&gt;]));&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;      &lt;/span&gt;&lt;span style="font-style: italic;color: #808080;"&gt;//Output&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;      std::cout &amp;lt;&amp;lt; (*obj1)() &amp;lt;&amp;lt; &lt;/span&gt;&lt;span style="color: #ff00ff;"&gt;'\n'&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;                &amp;lt;&amp;lt; (*obj2)() &amp;lt;&amp;lt; &lt;/span&gt;&lt;span style="color: #ff00ff;"&gt;'\n'&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;                &amp;lt;&amp;lt; (*obj3)() &amp;lt;&amp;lt; &lt;/span&gt;&lt;span style="color: #ff00ff;"&gt;'\n'&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;                &amp;lt;&amp;lt; std::flush;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;      &lt;/span&gt;&lt;span style="font-style: italic;color: #808080;"&gt;//Cleanup&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;      &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;delete&lt;/span&gt;&lt;span style="color: #000000;"&gt; obj1;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;      &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;delete&lt;/span&gt;&lt;span style="color: #000000;"&gt; obj2;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;      &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;delete&lt;/span&gt;&lt;span style="color: #000000;"&gt; obj3;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;    }&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;    &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;catch&lt;/span&gt;&lt;span style="color: #000000;"&gt; (&lt;/span&gt;&lt;span style="color: #800000;"&gt;const&lt;/span&gt;&lt;span style="color: #000000;"&gt; std::exception &amp;amp;e) { std::cout &amp;lt;&amp;lt; &lt;/span&gt;&lt;span style="color: #dd0000;"&gt;"Error occured: "&lt;/span&gt;&lt;span style="color: #000000;"&gt; &amp;lt;&amp;lt; e.what() &amp;lt;&amp;lt; std::endl; }&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  }&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;return&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000ff;"&gt;0&lt;/span&gt;&lt;span style="color: #000000;"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Output:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;/tmp&amp;gt; g++-4.4 -Wall -o abstract_factory_test abstract_factory_test.cpp&lt;br /&gt;/tmp&amp;gt; ./abstract_factory_test b 2&lt;br /&gt;3&lt;br /&gt;5&lt;br /&gt;6&lt;br /&gt;/tmp&amp;gt; ./abstract_factory_test b 3&lt;br /&gt;3&lt;br /&gt;6&lt;br /&gt;7&lt;br /&gt;/tmp&amp;gt; ./abstract_factory_test d 2&lt;br /&gt;2&lt;br /&gt;6&lt;br /&gt;8&lt;br /&gt;/tmp&amp;gt; ./abstract_factory_test d 3&lt;br /&gt;2&lt;br /&gt;9&lt;br /&gt;12&lt;br /&gt;/tmp&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Hopefully you should now be able to take this example and plug it in just about anywhere. Easy to add new types. No need to modify existing classes. Fully dynamic. Easy to use!&lt;br /&gt;&lt;br /&gt;This method really shines if you dynamically load derived classes while your program is running. Just make sure your DLL uses the the template function internally, so an instance of the function for the new type is created, and dynamically add an id to the map, and presto you're done.&lt;br /&gt;&lt;br /&gt;Now go out there and leverage the power of C++!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/833174317742362874-4792719090417915905?l=insanecoding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://insanecoding.blogspot.com/feeds/4792719090417915905/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=833174317742362874&amp;postID=4792719090417915905' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/833174317742362874/posts/default/4792719090417915905'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/833174317742362874/posts/default/4792719090417915905'/><link rel='alternate' type='text/html' href='http://insanecoding.blogspot.com/2010/07/simplifying-bootstrapping-for-virtual.html' title='Simplifying bootstrapping for virtual constructors'/><author><name>insane coder</name><uri>http://www.blogger.com/profile/06901386115570670209</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-833174317742362874.post-2502595210222735372</id><published>2010-07-20T06:55:00.000-07:00</published><updated>2010-07-21T14:47:15.720-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='good code'/><category scheme='http://www.blogger.com/atom/ns#' term='types'/><category scheme='http://www.blogger.com/atom/ns#' term='pure failure'/><category scheme='http://www.blogger.com/atom/ns#' term='Function Pointers'/><category scheme='http://www.blogger.com/atom/ns#' term='binary'/><category scheme='http://www.blogger.com/atom/ns#' term='bad code'/><category scheme='http://www.blogger.com/atom/ns#' term='insane ideas'/><category scheme='http://www.blogger.com/atom/ns#' term='factory'/><category scheme='http://www.blogger.com/atom/ns#' term='Optimization'/><title type='text'>Time to shutdown the factory for code violations</title><content type='html'>There's a common problem in software development regarding how to create an object's type dynamically in C++ and similar languages. If I have a collection of classes (they all inherit from the same base), I can use a base pointer to any instance, and perform operations as needed. The issue is generating that pointer in the first place.&lt;br /&gt;&lt;br /&gt;Say I have an image class, with subclasses of image_png, image_jpeg, image_gif, and so on. I can use an image pointer along with its virtual functions to do an operation like image_pointer-&gt;resize(new_dimensions), and have it do whatever needs to be done for the image type in question to resize it and write the data properly.&lt;br /&gt;&lt;br /&gt;This idea applies to all kinds of projects over and over again. Another example could be a compression class. Where I have the class compress, along with subclasses compress_zip, compress_gzip, compress_7zip, and so on. I can do compress_pointer-&gt;uncompress(in_file, out_file), and have that work appropriately with virtual functions.&lt;br /&gt;&lt;br /&gt;However my image pointer and my compress pointer need to be pointing at the right kind of object for this to work in the first place. My image is sent over the network, I have information at runtime of image/jpeg and the binary data, and I need to load that into the correct subclass image_jpeg. My compressed file is on the hard drive, I read its type via its extension or its header, again I need my pointer to point at the appropriate subtype. I don't have this information at compile time, so how do I initialize my pointer?&lt;br /&gt;&lt;br /&gt;In this case, the idea of virtual constructors, or &lt;a href="http://en.wikipedia.org/wiki/Factory_%28software_concept%29"&gt;factories&lt;/a&gt; come into play. The simplest factory would be in the form of an if/else if structure, or a switch.&lt;br /&gt;&lt;pre style="background-color:#F5F2D5"&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;image *image_factory(&lt;/span&gt;&lt;span style="color: #800000;"&gt;const&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #800000;"&gt;char&lt;/span&gt;&lt;span style="color: #000000;"&gt; *mime_type, &lt;/span&gt;&lt;span style="color: #800000;"&gt;const&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #800000;"&gt;uint8_t&lt;/span&gt;&lt;span style="color: #000000;"&gt; *binary_data, size_t size)&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;{&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  image *image_pointer;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;if&lt;/span&gt;&lt;span style="color: #000000;"&gt; (!strcmp(mime_type, &lt;/span&gt;&lt;span style="color: #dd0000;"&gt;"image/jpeg"&lt;/span&gt;&lt;span style="color: #000000;"&gt;)) { image_pointer = &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;new&lt;/span&gt;&lt;span style="color: #000000;"&gt; image_jpeg(binary_data, size); }&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;else&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;if&lt;/span&gt;&lt;span style="color: #000000;"&gt; (!strcmp(mime_type, &lt;/span&gt;&lt;span style="color: #dd0000;"&gt;"image/png"&lt;/span&gt;&lt;span style="color: #000000;"&gt;)) { image_pointer = &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;new&lt;/span&gt;&lt;span style="color: #000000;"&gt; image_png(binary_data, size); }&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;else&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;if&lt;/span&gt;&lt;span style="color: #000000;"&gt; (!strcmp(mime_type, &lt;/span&gt;&lt;span style="color: #dd0000;"&gt;"image/gif"&lt;/span&gt;&lt;span style="color: #000000;"&gt;)) { image_pointer = &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;new&lt;/span&gt;&lt;span style="color: #000000;"&gt; image_gif(binary_data, size); }&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;else&lt;/span&gt;&lt;span style="color: #000000;"&gt; { &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;throw&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;nbsp&lt;/span&gt;&lt;span style="color: #dd0000;"&gt;"Unsupported image type"&lt;/span&gt;&lt;span style="color: #000000;"&gt;; }&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;return&lt;/span&gt;&lt;span style="color: #000000;"&gt; image_pointer;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;pre style="background-color:#F5F2D5"&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;compress *compress_factory(COMPRESS_TYPES requested_save_format)&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;{&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  compress *compress_pointer;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;switch&lt;/span&gt;&lt;span style="color: #000000;"&gt; (requested_save_format)&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  {&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;    &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;case&lt;/span&gt;&lt;span style="color: #000000;"&gt; COMPRESS_ZIP: compress_pointer = &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;new&lt;/span&gt;&lt;span style="color: #000000;"&gt; compress_zip; &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;break&lt;/span&gt;&lt;span style="color: #000000;"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;    &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;case&lt;/span&gt;&lt;span style="color: #000000;"&gt; COMPRESS_GZIP: compress_pointer = &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;new&lt;/span&gt;&lt;span style="color: #000000;"&gt; compress_gzip; &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;break&lt;/span&gt;&lt;span style="color: #000000;"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;    &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;case&lt;/span&gt;&lt;span style="color: #000000;"&gt; COMPRESS_7ZIP: compress_pointer = &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;new&lt;/span&gt;&lt;span style="color: #000000;"&gt; compress_7zip; &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;break&lt;/span&gt;&lt;span style="color: #000000;"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;    &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;default&lt;/span&gt;&lt;span style="color: #000000;"&gt;: &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;throw&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;nbsp;std::runtime_error(&lt;/span&gt;&lt;span style="color: #dd0000;"&gt;"Unknown enum value"&lt;/span&gt;&lt;span style="color: #000000;"&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  }&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;return&lt;/span&gt;&lt;span style="color: #000000;"&gt; compress_pointer;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Now the above functions allow us to get the base pointer initialized appropriately, but they have some drawbacks.&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;A single function needs to know about every type.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;If which types are supported changes during runtime, perhaps based on which DLLs are found, the factory function becomes more complex, and has to be specifically tailored for each application.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;If there are multiple constructors, and in some cases one is needed, and in some cases another, suddenly we need to recreate the same logic in multiple factory functions, one factory function per constructor.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;This style of factory function has to be recreated for every single collection of classes present, the logic behind a factory function is not abstracted away.&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;Based on these drawbacks, obviously such a method is the incorrect solution, even though it is the most &lt;a href="http://en.wikipedia.org/wiki/Factory_method_pattern"&gt;popular method used&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;In the case where we have variables mapping to other variables, such as 1 = "Apple", 2 = "Orange", 3 = "Tomato", the obvious solution would be to setup an array or use a &lt;a href="http://en.wikipedia.org/wiki/Map_%28C%2B%2B%29"&gt;map&lt;/a&gt;. If the mapping needed is between an integer and a variable, going from integer -&gt; variable is simply a matter of indexing into an array. When dealing with non integer types, the standard &lt;a href="http://www.cplusplus.com/reference/stl/map/"&gt;std::map&lt;/a&gt; fits the bill rather nicely, as it can allow any type to become an index.&lt;br /&gt;&lt;br /&gt;So the question becomes, can we map a variable to a type itself? With a bit of bootstrapping, the answer is actually yes! What we need are &lt;a href="http://insanecoding.blogspot.com/2007/05/secrets-to-optimization-function.html"&gt;function pointers to replace code logic&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;We can't create a function pointer directly to a constructor, so we'll need a bit of bootstrapping. We can create function pointers to global functions, or &lt;a href="http://www.learncpp.com/cpp-tutorial/812-static-member-functions/"&gt;static member functions&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;In our compression case we can do the following:&lt;br /&gt;&lt;pre style="background-color:#F5F2D5"&gt;&lt;br /&gt;&lt;span style="color: #800000;"&gt;static&lt;/span&gt;&lt;span style="color: #000000;"&gt; compress *compress_zip::construct() { &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;return&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;new&lt;/span&gt;&lt;span style="color: #000000;"&gt; compress_zip; }&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #800000;"&gt;static&lt;/span&gt;&lt;span style="color: #000000;"&gt; compress *compress_gzip::construct() { &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;return&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;new&lt;/span&gt;&lt;span style="color: #000000;"&gt; compress_gzip; }&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #800000;"&gt;static&lt;/span&gt;&lt;span style="color: #000000;"&gt; compress *compress_7zip::construct() { &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;return&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;new&lt;/span&gt;&lt;span style="color: #000000;"&gt; compress_7zip; }&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;We'll place a static construct() within each of our classes we'd like to be able to instantiate dynamically, and then we can use them in a map like so:&lt;br /&gt;&lt;pre style="background-color:#F5F2D5"&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;std::map&amp;lt;COMPRESS_TYPES, compress *(*)()&amp;gt; compress_factory;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;compress_factory[COMPRESS_ZIP] = compress_zip::construct;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;compress_factory[COMPRESS_GZIP] = compress_gzip::construct;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;compress_factory[COMPRESS_7ZIP] = compress_7zip::construct;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Once we have a map in place that can be constructed at runtime, we no longer have most of our above issues. No canned function needs to be created which knows about all the supported types in advance, which needs modification for each new type. Values are only added to the map that the required DLLs were found for it, or other runtime constraints. The entire idea is also abstracted away, and we don't need to constantly recreate new factory functions for each family of objects. We simply just initialize a factory object and make use of it.&lt;br /&gt;&lt;br /&gt;Now how exactly do we use our map? The idea which is rather popular and expounded in book after book, is to create a factory template class something similar to the following:&lt;br /&gt;&lt;pre style="background-color:#F5F2D5"&gt;&lt;br /&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;template&lt;/span&gt;&lt;span style="color: #000000;"&gt; &amp;lt;&lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;typename&lt;/span&gt;&lt;span style="color: #000000;"&gt; identifier, &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;typename&lt;/span&gt;&lt;span style="color: #000000;"&gt; product, &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;typename&lt;/span&gt;&lt;span style="color: #000000;"&gt; function&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;struct&lt;/span&gt;&lt;span style="color: #000000;"&gt; factory&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;{&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="color: #800000;"&gt;void&lt;/span&gt;&lt;span style="color: #000000;"&gt; set_mapping(&lt;/span&gt;&lt;span style="color: #800000;"&gt;const&lt;/span&gt;&lt;span style="color: #000000;"&gt; identifier &amp;amp;id, function f) { mapping[id] = f; }&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  product *construct(&lt;/span&gt;&lt;span style="color: #800000;"&gt;const&lt;/span&gt;&lt;span style="color: #000000;"&gt; identifier &amp;amp;id)&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  {&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;    function f = mapping.at(id);&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;    &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;return&lt;/span&gt;&lt;span style="color: #000000;"&gt; f();&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  }&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;private&lt;/span&gt;&lt;span style="color: #000000;"&gt;:&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  std::map&amp;lt;identifier, function&amp;gt; mapping;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;};&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Now that we have all that encapsulated, we can do the following:&lt;br /&gt;&lt;pre style="background-color:#F5F2D5"&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;factory&amp;lt;COMPRESS_TYPES, compress, compress *(*)()&amp;gt; myfactory;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;myfactory.set_mapping(COMPRESS_ZIP, compress_zip::construct);&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;...&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;compress *compress_pointer = myfactory.construct(requested_save_format);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;However, such a method has a serious drawback. What if my constructor needs parameters? As it does in the image example above? Do I end up creating a new factory encapsulation class each time? &lt;a href="http://loki-lib.cvs.sourceforge.net/viewvc/loki-lib/loki/include/loki/Factory.h?revision=1.17&amp;view=markup"&gt;One library out there solves this problem with ~800 lines of code&lt;/a&gt;. Basically the construct function in the factory class is overloaded a bunch of times with template parameters over and over again, for some conceivable amount of parameters a function might take.&lt;br /&gt;&lt;pre style="background-color:#F5F2D5"&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;AbstractProduct *CreateObject(&lt;/span&gt;&lt;span style="color: #800000;"&gt;const&lt;/span&gt;&lt;span style="color: #000000;"&gt; IdentifierType &amp;amp;id,&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;                              Parm1 p1, Parm2 p2, Parm3 p3, Parm4 p4, Parm5 p5, Parm6 p6, Parm7 p7, Parm8 p8)&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;{&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;typename&lt;/span&gt;&lt;span style="color: #000000;"&gt; IdToProductMap::iterator i = associations_.find(id);&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;if&lt;/span&gt;&lt;span style="color: #000000;"&gt; (i != associations_.end()) { &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;return&lt;/span&gt;&lt;span style="color: #000000;"&gt; (i-&amp;gt;second)(p1, p2, p3, p4, p5, p6, p7, p8); }&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;return&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;this&lt;/span&gt;&lt;span style="color: #000000;"&gt;-&amp;gt;OnUnknownType(id);&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The above snippet is repeated 16 times in that library with 0-15 parameters. First of all, such code commits the unforgivable sin of code repetition, and is limited to 15 parameters. What if I need more? Sin more?&lt;br /&gt;&lt;br /&gt;The entire idea of a factory which produces an object within itself needs to be shutdown. By trying to be overly clever and encapsulate more than needed, object factories turn into nothing but bloat and horrible code.&lt;br /&gt;&lt;br /&gt;Simplicity is king. Therefore, the map should NOT be encapsulated, nor should an object be directly produced. Our so called factory should only produce the appropriate mold needed to form our object.&lt;br /&gt;&lt;br /&gt;In the case of images:&lt;br /&gt;&lt;pre style="background-color:#F5F2D5"&gt;&lt;br /&gt;&lt;span style="color: #800000;"&gt;static&lt;/span&gt;&lt;span style="color: #000000;"&gt; image *image_jpeg::construct(&lt;/span&gt;&lt;span style="color: #800000;"&gt;const&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #800000;"&gt;uint8_t&lt;/span&gt;&lt;span style="color: #000000;"&gt; *binary_data, size_t size)&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;{&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;return&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;new&lt;/span&gt;&lt;span style="color: #000000;"&gt; image_jpeg(binary_data, size);&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #800000;"&gt;static&lt;/span&gt;&lt;span style="color: #000000;"&gt; image *image_png::construct(&lt;/span&gt;&lt;span style="color: #800000;"&gt;const&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #800000;"&gt;uint8_t&lt;/span&gt;&lt;span style="color: #000000;"&gt; *binary_data, size_t size)&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;{&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;return&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;new&lt;/span&gt;&lt;span style="color: #000000;"&gt; image_png(binary_data, size);&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #800000;"&gt;static&lt;/span&gt;&lt;span style="color: #000000;"&gt; image *image_gif::construct(&lt;/span&gt;&lt;span style="color: #800000;"&gt;const&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #800000;"&gt;uint8_t&lt;/span&gt;&lt;span style="color: #000000;"&gt; *binary_data, size_t size)&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;{&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;return&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;new&lt;/span&gt;&lt;span style="color: #000000;"&gt; image_gif(binary_data, size);&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;std::map&amp;lt;std::string, image *(*)(&lt;/span&gt;&lt;span style="color: #800000;"&gt;const&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #800000;"&gt;uint8_t&lt;/span&gt;&lt;span style="color: #000000;"&gt; *, size_t)&amp;gt; image_factory;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;image_factory[&lt;/span&gt;&lt;span style="color: #dd0000;"&gt;"image/jpeg"&lt;/span&gt;&lt;span style="color: #000000;"&gt;] = image_jpeg::construct;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;image_factory[&lt;/span&gt;&lt;span style="color: #dd0000;"&gt;"image/png"&lt;/span&gt;&lt;span style="color: #000000;"&gt;] = image_png::construct;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;image_factory[&lt;/span&gt;&lt;span style="color: #dd0000;"&gt;"image/gif"&lt;/span&gt;&lt;span style="color: #000000;"&gt;] = image_gif::construct;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Now to create an image, simply do the following when you want to create an image based on run time variables:&lt;br /&gt;&lt;pre style="background-color:#F5F2D5"&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;image *image_pointer = image_factory.at(mime_type)(binary_data, size);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Notice that code would take the place of:&lt;br /&gt;&lt;pre style="background-color:#F5F2D5"&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;image *image_pointer = &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;new&lt;/span&gt;&lt;span style="color: #000000;"&gt; image_png(binary_data, size);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Now the creation of a particular object at runtime looks pretty much like creating a specific object, and can feel natural. Just like new which throws an error when it fails (which can happen here too), std::map::at() throws an error when the requested index is not found, so you can reuse the same type of exception handling you're already using when creating objects in general.&lt;br /&gt;&lt;br /&gt;If you'd like a complete example which you can play with yourself, try this:&lt;br /&gt;&lt;pre style="background-color:#F5F2D5"&gt;&lt;br /&gt;&lt;span style="color: #008000;"&gt;#include &amp;lt;iostream&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #008000;"&gt;#include &amp;lt;string&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #008000;"&gt;#include &amp;lt;map&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #008000;"&gt;#include &amp;lt;stdexcept&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #008000;"&gt;#include &amp;lt;cstdlib&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;class&lt;/span&gt;&lt;span style="color: #000000;"&gt; Base&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;{&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="color: #800000;"&gt;int&lt;/span&gt;&lt;span style="color: #000000;"&gt; x, y;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;public&lt;/span&gt;&lt;span style="color: #000000;"&gt;:&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  Base(&lt;/span&gt;&lt;span style="color: #800000;"&gt;int&lt;/span&gt;&lt;span style="color: #000000;"&gt; x, &lt;/span&gt;&lt;span style="color: #800000;"&gt;int&lt;/span&gt;&lt;span style="color: #000000;"&gt; y) : x(x), y(y) {}&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;virtual&lt;/span&gt;&lt;span style="color: #000000;"&gt; ~Base() {};&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;virtual&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #800000;"&gt;int&lt;/span&gt;&lt;span style="color: #000000;"&gt; mult() { &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;return&lt;/span&gt;&lt;span style="color: #000000;"&gt; x*y; }&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;virtual&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #800000;"&gt;int&lt;/span&gt;&lt;span style="color: #000000;"&gt; add() { &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;return&lt;/span&gt;&lt;span style="color: #000000;"&gt; x+y; }&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="color: #800000;"&gt;static&lt;/span&gt;&lt;span style="color: #000000;"&gt; Base *create(&lt;/span&gt;&lt;span style="color: #800000;"&gt;int&lt;/span&gt;&lt;span style="color: #000000;"&gt; x, &lt;/span&gt;&lt;span style="color: #800000;"&gt;int&lt;/span&gt;&lt;span style="color: #000000;"&gt; y) { &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;return&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;new&lt;/span&gt;&lt;span style="color: #000000;"&gt; Base(x, y); }&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;};&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;class&lt;/span&gt;&lt;span style="color: #000000;"&gt; Derived : &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;public&lt;/span&gt;&lt;span style="color: #000000;"&gt; Base&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;{&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="color: #800000;"&gt;int&lt;/span&gt;&lt;span style="color: #000000;"&gt; z;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;public&lt;/span&gt;&lt;span style="color: #000000;"&gt;:&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  Derived(&lt;/span&gt;&lt;span style="color: #800000;"&gt;int&lt;/span&gt;&lt;span style="color: #000000;"&gt; x, &lt;/span&gt;&lt;span style="color: #800000;"&gt;int&lt;/span&gt;&lt;span style="color: #000000;"&gt; y) : Base(x, y), z(&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;1&lt;/span&gt;&lt;span style="color: #000000;"&gt;) {}&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="color: #800000;"&gt;void&lt;/span&gt;&lt;span style="color: #000000;"&gt; setZ(&lt;/span&gt;&lt;span style="color: #800000;"&gt;int&lt;/span&gt;&lt;span style="color: #000000;"&gt; z) { &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;this&lt;/span&gt;&lt;span style="color: #000000;"&gt;-&amp;gt;z = z; }&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;virtual&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #800000;"&gt;int&lt;/span&gt;&lt;span style="color: #000000;"&gt; mult() { &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;return&lt;/span&gt;&lt;span style="color: #000000;"&gt; Base::mult()*z; }&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;virtual&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #800000;"&gt;int&lt;/span&gt;&lt;span style="color: #000000;"&gt; add() { &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;return&lt;/span&gt;&lt;span style="color: #000000;"&gt; Base::add()+z; }&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="color: #800000;"&gt;static&lt;/span&gt;&lt;span style="color: #000000;"&gt; Base *create(&lt;/span&gt;&lt;span style="color: #800000;"&gt;int&lt;/span&gt;&lt;span style="color: #000000;"&gt; x, &lt;/span&gt;&lt;span style="color: #800000;"&gt;int&lt;/span&gt;&lt;span style="color: #000000;"&gt; y) { &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;return&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;new&lt;/span&gt;&lt;span style="color: #000000;"&gt; Derived(x, y); }&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;};&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #800000;"&gt;int&lt;/span&gt;&lt;span style="color: #000000;"&gt; main(&lt;/span&gt;&lt;span style="color: #800000;"&gt;int&lt;/span&gt;&lt;span style="color: #000000;"&gt; argc, &lt;/span&gt;&lt;span style="color: #800000;"&gt;const&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #800000;"&gt;char&lt;/span&gt;&lt;span style="color: #000000;"&gt; *&lt;/span&gt;&lt;span style="color: #800000;"&gt;const&lt;/span&gt;&lt;span style="color: #000000;"&gt; *&lt;/span&gt;&lt;span style="color: #800000;"&gt;const&lt;/span&gt;&lt;span style="color: #000000;"&gt; argv)&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;{&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="font-style: italic;color: #808080;"&gt;//Get factory ready&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  std::map&amp;lt;std::string, Base *(*)(&lt;/span&gt;&lt;span style="color: #800000;"&gt;int&lt;/span&gt;&lt;span style="color: #000000;"&gt;, &lt;/span&gt;&lt;span style="color: #800000;"&gt;int&lt;/span&gt;&lt;span style="color: #000000;"&gt;)&amp;gt; factory;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="font-style: italic;color: #808080;"&gt;//Add some rules&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  factory[&lt;/span&gt;&lt;span style="color: #dd0000;"&gt;"base"&lt;/span&gt;&lt;span style="color: #000000;"&gt;] = Base::create;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  factory[&lt;/span&gt;&lt;span style="color: #dd0000;"&gt;"derived"&lt;/span&gt;&lt;span style="color: #000000;"&gt;] = Derived::create;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;try&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  {&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;    &lt;/span&gt;&lt;span style="font-style: italic;color: #808080;"&gt;//Instantiate based on run-time variables&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;    Base *obj = factory.at(argv[&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;1&lt;/span&gt;&lt;span style="color: #000000;"&gt;])(&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;4&lt;/span&gt;&lt;span style="color: #000000;"&gt;, &lt;/span&gt;&lt;span style="color: #0000ff;"&gt;5&lt;/span&gt;&lt;span style="color: #000000;"&gt;); &lt;/span&gt;&lt;span style="font-style: italic;color: #808080;"&gt;//Note: instead of new Base(4, 5) or new Derived(4, 5)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;    &lt;/span&gt;&lt;span style="font-style: italic;color: #808080;"&gt;//Set Z if derived and requested&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;    &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;if&lt;/span&gt;&lt;span style="color: #000000;"&gt; (argc &amp;gt; &lt;/span&gt;&lt;span style="color: #0000ff;"&gt;2&lt;/span&gt;&lt;span style="color: #000000;"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;    {&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;      &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;if&lt;/span&gt;&lt;span style="color: #000000;"&gt; (Derived *d = &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;dynamic_cast&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;lt;Derived *&amp;gt;(obj)) { d-&amp;gt;setZ(std::atoi(argv[&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;2&lt;/span&gt;&lt;span style="color: #000000;"&gt;])); }&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;    }&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;    &lt;/span&gt;&lt;span style="font-style: italic;color: #808080;"&gt;//Output&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;    std::cout &amp;lt;&amp;lt; obj-&amp;gt;mult() &amp;lt;&amp;lt; &lt;/span&gt;&lt;span style="color: #ff00ff;"&gt;' '&lt;/span&gt;&lt;span style="color: #000000;"&gt; &amp;lt;&amp;lt; obj-&amp;gt;add() &amp;lt;&amp;lt; std::endl;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;    &lt;/span&gt;&lt;span style="font-style: italic;color: #808080;"&gt;//Cleanup&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;    &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;delete&lt;/span&gt;&lt;span style="color: #000000;"&gt; obj;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  }&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;catch&lt;/span&gt;&lt;span style="color: #000000;"&gt; (&lt;/span&gt;&lt;span style="color: #800000;"&gt;const&lt;/span&gt;&lt;span style="color: #000000;"&gt; std::exception &amp;amp;e) { std::cout &amp;lt;&amp;lt; &lt;/span&gt;&lt;span style="color: #dd0000;"&gt;"Error occured: "&lt;/span&gt;&lt;span style="color: #000000;"&gt; &amp;lt;&amp;lt; e.what() &amp;lt;&amp;lt; std::endl; }&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="font-weight: bold;color: #000000;"&gt;return&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000ff;"&gt;0&lt;/span&gt;&lt;span style="color: #000000;"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #000000;"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Here's what the output looks like:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;/tmp&amp;gt; g++-4.4 -Wall -o factory_test factory_test.cpp&lt;br /&gt;/tmp&amp;gt; ./factory_test&lt;br /&gt;Error occured: basic_string::_S_construct NULL not valid&lt;br /&gt;/tmp&amp;gt; ./factory_test base&lt;br /&gt;20 9&lt;br /&gt;/tmp&amp;gt; ./factory_test derived&lt;br /&gt;20 10&lt;br /&gt;/tmp&amp;gt; ./factory_test derived 6&lt;br /&gt;120 15&lt;br /&gt;/tmp&amp;gt; ./factory_test cows&lt;br /&gt;Error occured: map::at&lt;br /&gt;/tmp&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Basically the only issue we're left with is that for each class you want to be able to use a factory for, you have to create a static member function for each constructor you want to use with a particular factory. I don't think there is away around that. It's a minor inconvenience, but in the end offers a lot of power in a clean fashion.&lt;br /&gt;&lt;br /&gt;This idea of combining a map with a function pointer can be expanded to other areas as well. You can use this method for calling functions in general based on any runtime input. If your class has many different member functions, each with the same parameters, but for different operations, consider creating a map to &lt;a href="http://www.parashift.com/c%2B%2B-faq-lite/pointers-to-members.html"&gt;member function pointers&lt;/a&gt;, and use the input as an index into a map to call the appropriate member function.&lt;br /&gt;&lt;br /&gt;Suggestions, improvements, and comments welcome.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/833174317742362874-2502595210222735372?l=insanecoding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://insanecoding.blogspot.com/feeds/2502595210222735372/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=833174317742362874&amp;postID=2502595210222735372' title='12 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/833174317742362874/posts/default/2502595210222735372'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/833174317742362874/posts/default/2502595210222735372'/><link rel='alternate' type='text/html' href='http://insanecoding.blogspot.com/2010/07/time-to-shutdown-factory-for-code.html' title='Time to shutdown the factory for code violations'/><author><name>insane coder</name><uri>http://www.blogger.com/profile/06901386115570670209</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>12</thr:total></entry><entry><id>tag:blogger.com,1999:blog-833174317742362874.post-1742684663998488556</id><published>2010-06-03T14:19:00.000-07:00</published><updated>2010-06-03T14:56:15.083-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Mozilla'/><category scheme='http://www.blogger.com/atom/ns#' term='Library'/><category scheme='http://www.blogger.com/atom/ns#' term='Windows'/><category scheme='http://www.blogger.com/atom/ns#' term='iphone'/><category scheme='http://www.blogger.com/atom/ns#' term='closed source'/><category scheme='http://www.blogger.com/atom/ns#' term='Firefox'/><category scheme='http://www.blogger.com/atom/ns#' term='competition'/><category scheme='http://www.blogger.com/atom/ns#' term='open source'/><category scheme='http://www.blogger.com/atom/ns#' term='bugs'/><category scheme='http://www.blogger.com/atom/ns#' term='parameters'/><category scheme='http://www.blogger.com/atom/ns#' term='pure failure'/><category scheme='http://www.blogger.com/atom/ns#' term='compatibility'/><category scheme='http://www.blogger.com/atom/ns#' term='API'/><category scheme='http://www.blogger.com/atom/ns#' term='binary'/><category scheme='http://www.blogger.com/atom/ns#' term='Mac OS X'/><category scheme='http://www.blogger.com/atom/ns#' term='Portability'/><category scheme='http://www.blogger.com/atom/ns#' term='Optimization'/><title type='text'>Undocumented APIs</title><content type='html'>This topic has been kicked around all over for at least a decade. It's kind of hard to read a computer programming magazine, third party documentation, technology article site, third party developer mailing list or the like without running into it.&lt;br /&gt;&lt;br /&gt;Inevitably someone always mentions how some Operating System has undocumented APIs, and the creators of the OS are using those undocumented APIs, but telling third party developers not to use them. There will always be the rant about unfair competition, hypocrisy, and other evils.&lt;br /&gt;&lt;br /&gt;Large targets are Microsoft and Apple, for creating undocumented APIs that are used by Internet Explorer, Microsoft Office, Safari, iPhone development, and other in-house applications. To the detriment of Mozilla, OpenOffice.org, third parties, and hobbyist developer teams.&lt;br /&gt;&lt;br /&gt;If you wrote one of those articles/rants/complaints, or agreed with them, I'm asking you to turn in your Geek Membership card now. You're too stupid, too idiotic, too dumb, too nearsighted, and too vilifying (add other derogatory adjectives you can think of) to be part of our club. You have no business writing code or even discussing programming.&lt;br /&gt;&lt;br /&gt;Operating Systems and other applications that communicate via APIs provide public interfaces that are supposed to be stable. If you find a function in official public documentation, that generally signifies it is safe to use the function in question, and the company will support it for the foreseeable future versions. If a function is undocumented, it's because the company doesn't think they will be supporting the function long term.&lt;br /&gt;&lt;br /&gt;Now new versions which provide even the exact same API inevitably break things. It is so much worse for APIs which you're not supposed to be using in the first place. Yet people who complain about undocumented APIs, also complain when the new version removes a function they were using. They blame the company for purposely removing features they knew competition or hobbyists were using. That's where the real hypocrisy is.&lt;br /&gt;&lt;br /&gt;As much as you hate a new version breaking your existing software, so does Microsoft, Apple, and others. The popularity of their products is tied to what third party applications exist. Having popular third party applications break on new versions is a bad thing. That's why they don't document APIs they plan on changing.&lt;br /&gt;&lt;br /&gt;Now why do they use them then? Simple, you can write better software when you intimately understand the platform you're developing for, and write the most direct code possible. When issues occur because of their use, it's easy for the in-house teams to test their own software for compatibility with upcoming versions and fix them. If Microsoft sees a new version of Windows break Internet Explorer, they can easily patch the Internet Explorer provided with the upcoming version, or provide a new version altogether. But don't expect them to go patching third party applications, especially ones which they don't have the source to. They may have done so in the past, and introduced compatibility hacks, but this really isn't their problem, and you should be grateful when they go out of their way to do so.&lt;br /&gt;&lt;br /&gt;So quit your complaining about undocumented APIs, or please go around introducing yourself as "&lt;a href="http://www.dilbert.com/dyn/str_strip/000000000/00000000/0000000/000000/00000/1000/200/1233/1233.strip.print.gif"&gt;The Dumb One&lt;/a&gt;".&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/833174317742362874-1742684663998488556?l=insanecoding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://insanecoding.blogspot.com/feeds/1742684663998488556/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=833174317742362874&amp;postID=1742684663998488556' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/833174317742362874/posts/default/1742684663998488556'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/833174317742362874/posts/default/1742684663998488556'/><link rel='alternate' type='text/html' href='http://insanecoding.blogspot.com/2010/06/undocumented-apis.html' title='Undocumented APIs'/><author><name>insane coder</name><uri>http://www.blogger.com/profile/06901386115570670209</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-833174317742362874.post-4615312562166259836</id><published>2010-03-27T15:21:00.000-07:00</published><updated>2010-03-28T01:14:30.924-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='x86-64'/><category scheme='http://www.blogger.com/atom/ns#' term='Library'/><category scheme='http://www.blogger.com/atom/ns#' term='bad code'/><category scheme='http://www.blogger.com/atom/ns#' term='C++-0x'/><category scheme='http://www.blogger.com/atom/ns#' term='unsigned'/><category scheme='http://www.blogger.com/atom/ns#' term='bugs'/><category scheme='http://www.blogger.com/atom/ns#' term='good code'/><category scheme='http://www.blogger.com/atom/ns#' term='parameters'/><category scheme='http://www.blogger.com/atom/ns#' term='types'/><category scheme='http://www.blogger.com/atom/ns#' term='signed'/><category scheme='http://www.blogger.com/atom/ns#' term='pure failure'/><category scheme='http://www.blogger.com/atom/ns#' term='x86'/><category scheme='http://www.blogger.com/atom/ns#' term='API'/><category scheme='http://www.blogger.com/atom/ns#' term='binary'/><category scheme='http://www.blogger.com/atom/ns#' term='secure'/><category scheme='http://www.blogger.com/atom/ns#' term='C++-201x'/><category scheme='http://www.blogger.com/atom/ns#' term='c99'/><category scheme='http://www.blogger.com/atom/ns#' term='standards compliance'/><category scheme='http://www.blogger.com/atom/ns#' term='language'/><category scheme='http://www.blogger.com/atom/ns#' term='Portability'/><title type='text'>Does anyone understand types and magnitudes?</title><content type='html'>Regularly I have to work with many popular libraries out there, as well as many libraries written by coworkers and similar.&lt;br /&gt;&lt;br /&gt;One thing which I see constantly misused over and over again is the type system used in C and C++.&lt;br /&gt;&lt;br /&gt;I wonder if most people understand it, have bothered to contemplate it, or simply don't care if their library is misprogrammed trash.&lt;br /&gt;&lt;br /&gt;First of all, C/C++ for integers supports both &lt;span style="font-style:italic;"&gt;signed&lt;/span&gt; and &lt;span style="font-style:italic;"&gt;unsigned&lt;/span&gt; types. Many programmers seem to ignore the unsigned types altogether. Maybe some education is in order.&lt;br /&gt;&lt;br /&gt;Each base type in C consists of one or more bytes. Each byte on modern main stream systems are 8 bits to a byte. Meaning a single byte can store &lt;span style="font-family: arial;"&gt;&lt;span style="font-weight:bold;font-size:large;"&gt;2&lt;/span&gt;&lt;sup style="font-size:x-small;"&gt;8&lt;/sup&gt;&lt;/span&gt; values, or in other words &lt;span style="font-family: arial;"&gt;256&lt;/span&gt; possibilities. Two bytes can store &lt;span style="font-family: arial;"&gt;&lt;span style="font-weight:bold;font-size:large;"&gt;2&lt;/span&gt;&lt;sup style="font-size:x-small;"&gt;16&lt;/sup&gt;&lt;/span&gt; values, or in other words &lt;span style="font-family: arial;"&gt;65,536&lt;/span&gt; possibilities.&lt;br /&gt;&lt;br /&gt;A type designed for integers (whole numbers) which is unsigned will operate with the meaning of its values as ranging from 0 till amount of possibilities - 1. In the case of a one byte type: 0 to &lt;span style="font-family: arial;"&gt;255&lt;/span&gt;, for a 2 byte type: 0 to &lt;span style="font-family: arial;"&gt;65,535&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;When a value is signed (the usual default if no &lt;span style="font-style:italic;"&gt;signed&lt;/span&gt; or &lt;span style="font-style:italic;"&gt;unsigned&lt;/span&gt; description is applied), a single bit is used to describe whether the rest of the bits represent a positive or negative value. This effectively cuts the amount of positive values that can be represented in half. In the case of a single byte, &lt;span style="font-family: arial;"&gt;&lt;span style="font-weight:bold;font-size:large;"&gt;2&lt;/span&gt;&lt;sup style="font-size:x-small;"&gt;7&lt;/sup&gt;&lt;/span&gt; values will be negative, &lt;span style="font-family: arial;"&gt;-128&lt;/span&gt; to -1, &lt;span style="font-family: arial;"&gt;&lt;span style="font-weight:bold;font-size:large;"&gt;2&lt;/span&gt;&lt;sup style="font-size:x-small;"&gt;7&lt;/sup&gt;&lt;/span&gt;-1 values will be distinctly positive, 1 to &lt;span style="font-family: arial;"&gt;127&lt;/span&gt;, and one value will be 0 (for a total of &lt;span style="font-family: arial;"&gt;256&lt;/span&gt; possibilities). This same math extends to as many bytes being used in a given type.&lt;br /&gt;&lt;br /&gt;When dealing with something which requires working with both positive and negative values such as debt (monetary balance), direction, difference, relative position, and things of a similar nature, signed values is quite natural and should of course be used.&lt;br /&gt;&lt;br /&gt;But if you're working with something which has no meaning for negative values such as "Number of students in this class", "How old are you", "Amount of chickens in the coop", "Amount of rows in database table", or "Amount of elements in this array", or amounts of any nature really, using a signed type is one of the worst things you could possibly do. You are reserving half of your possible values for a situation which will never occur (barring mistakes in programming).&lt;br /&gt;&lt;br /&gt;Let's take a look at some real world examples. The most popular type used for at least the past decade would have to be the 32 bit integer. &lt;span style="font-family: arial;"&gt;&lt;span style="font-weight:bold;font-size:large;"&gt;2&lt;/span&gt;&lt;sup style="font-size:x-small;"&gt;32&lt;/sup&gt;&lt;/span&gt; gives us &lt;span style="font-family: arial;"&gt;4,294,967,296&lt;/span&gt; different value possibilities. If that was a storage size, it would be 4GB. Effectively a 32 bit unsigned integer can store the values 0 to &lt;span style="font-family: arial;"&gt;4,294,967,295&lt;/span&gt;, or one byte less than 4GB. If it was signed, it would be able to store the values &lt;span style="font-family: arial;"&gt;-2,147,483,648&lt;/span&gt; to &lt;span style="font-family: arial;"&gt;2,147,483,6487&lt;/span&gt;, topping out at one less than 2GB.&lt;br /&gt;&lt;br /&gt;If you have an Operating System or File System which limits you to 2GB as a max size for files, or your Digital Camera only lets you use up to 2GB flash cards, it's because the idiots that programmed it used signed values. They did this because either they were expecting files and flash cards of negative size, or because they were a bunch of idiots. Which of those two possibilities actually happened should be obvious.&lt;br /&gt;&lt;br /&gt;The same goes for any programming library you see with a limit of 2GB. As soon as you hear anyone mention a limitation of 2GB, what should immediately register in your head is that idiots worked on this application/library/standard/device.&lt;br /&gt;&lt;br /&gt;Now sometimes programmers try to justify their ignorance or their idiocy with remarks such as using negative values to indicate error conditions. Meaning, they write functions which return a positive value in case of success, and -1 in case of error. This is a very bad practice for two reasons. First of all, one shouldn't use a single variable to indicate two different things. It's okay to use a single variable where each bit (or sets of bits) indicate a flag for a set of flags. But it's very wrong to have a single value indicate success/failure and amount, or day of week and favorite color, or any two completely unrelated things like that. Doing so only leads to sloppy code, and should always be avoided. Second of all, you're cutting your amount of usable possibilities in half, and reserving a ton of values just for a single possibility. You can't be more wasteful than that.&lt;br /&gt;&lt;br /&gt;If you need a way for your function to return success/failure and amount, there are cleaner and more effective ways to do so. Many times an amount of 0 is invalid. If a function is supposed to return the amount of something, 0 isn't really an amount. If I asked how many students are in my class, and I get 0, that in itself should be indicative of an error. If I asked how many rows did my SQL statement just change, and I get 0, that should be indicative of an error, or at the very least, there were no SQL rows to change. If I really need to know if the 0 means a real error, or there was no data to work with, a separate function can tell me if the last call was a success or failure. In C and in POSIX, it is common to use the global variable &lt;span style="font-style:italic;"&gt;errno&lt;/span&gt; to indicate errors. If you're making your own library, you can make a function to tell you &lt;span style="font-style:italic;"&gt;why&lt;/span&gt; the last value was 0. There was no data, there was an error accessing the data, and so on.&lt;br /&gt;&lt;br /&gt;Another method would be to pass one parameter by pointer/reference to store the amount or success state, and have the other returned from the function. Another technique would be to return an &lt;span style="font-style:italic;"&gt;enum&lt;/span&gt; which tells you which error condition happened or everything is okay, and use a different function to retrieve the value of that operation upon success. Lastly, C++ programmers can use std::pair&lt;&gt; for all their multiple return needs, or simply return the amount normally, and throw an exception on any kind of error.&lt;br /&gt;&lt;br /&gt;Now that hopefully all my loyal readers are now more educated about the sign of their types, and various function return techniques that better libraries use, let's talk a bit about magnitude.&lt;br /&gt;&lt;br /&gt;I see again and again libraries that don't have a clue about magnitude. The various C/C++ standards state the following about the normal built in types.&lt;br /&gt;&lt;br /&gt;1) The amount of bytes used for the following types should be in this proportion: short &lt;= int &lt;= long &lt;= long long.&lt;br /&gt;2) short should be &lt;span style="font-weight:bold;"&gt;at least&lt;/span&gt; 2 bytes.&lt;br /&gt;3) long should be &lt;span style="font-weight:bold;"&gt;at least&lt;/span&gt; 4 bytes.&lt;br /&gt;4) long long should be &lt;span style="font-weight:bold;"&gt;at least&lt;/span&gt; 8 bytes;.&lt;br /&gt;&lt;br /&gt;Which means all these scenarios are perfectly legal:&lt;br /&gt;sizeof(short) == 2&lt;br /&gt;sizeof(int) == 2&lt;br /&gt;sizeof(long) == 4&lt;br /&gt;sizeof(long long) == 8&lt;br /&gt;&lt;br /&gt;sizeof(short) == 2&lt;br /&gt;sizeof(int) == 4&lt;br /&gt;sizeof(long) == 4&lt;br /&gt;sizeof(long long) == 8&lt;br /&gt;&lt;br /&gt;sizeof(short) == 2&lt;br /&gt;sizeof(int) == 4&lt;br /&gt;sizeof(long) == 8&lt;br /&gt;sizeof(long long) == 8&lt;br /&gt;&lt;br /&gt;sizeof(short) == 2&lt;br /&gt;sizeof(int) == 4&lt;br /&gt;sizeof(long) == 8&lt;br /&gt;sizeof(long long) == 16&lt;br /&gt;&lt;br /&gt;sizeof(short) == 4&lt;br /&gt;sizeof(int) == 4&lt;br /&gt;sizeof(long) == 8&lt;br /&gt;sizeof(long long) == 16&lt;br /&gt;&lt;br /&gt;sizeof(short) == 4&lt;br /&gt;sizeof(int) == 8&lt;br /&gt;sizeof(long) == 16&lt;br /&gt;sizeof(long long) == 32&lt;br /&gt;&lt;br /&gt;And so on.&lt;br /&gt;&lt;br /&gt;In order to get types of a particular size, C99 added the header &amp;lt;stdint.h&amp;gt; and C++-201x added &amp;lt;cstdint&amp;gt;, with types such as int8_t, uint8_t, int16_t, uint16_t, int32_t, uint32_t, int64_t, uint64_t, and several others. Each of these types are the size in bits that their name indicates, with those without a &lt;span style="font-style:italic;"&gt;u&lt;/span&gt; at the beginning being signed, and those with being unsigned. Using these types you can get the exact size you need.&lt;br /&gt;&lt;br /&gt;But remember to use things appropriately. I see several popular SQL engines for example that support as many rows in a table as a uint64_t is able to contain, but if you ask them how many rows were altered by the last query, they'll report that information in a plain and simple &lt;span style="font-style:italic;"&gt;int&lt;/span&gt;! You by now should realize there are two problems with such a course of action.&lt;br /&gt;&lt;br /&gt;Now lastly, if you're writing some kind of function which takes an array, it is normal convention to pass a pointer to the array, as well as a size variable to specify how many elements or bytes are within the array.&lt;br /&gt;&lt;br /&gt;The standard C library uses a type called &lt;span style="font-style:italic;"&gt;size_t&lt;/span&gt; to deal with such values. A &lt;span style="font-style:italic;"&gt;size_t&lt;/span&gt; can contain the highest amount of bytes the program is able to address, and is of course unsigned.&lt;br /&gt;&lt;br /&gt;If you need to pass an array, your prototype should always be along the lines of:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;void func(void *p, size_t size);&lt;br /&gt;void func(uint8_t *p, size_t size);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;If you need to return a size, for something which is addressable memory, again always use a &lt;span style="font-style:italic;"&gt;size_t&lt;/span&gt;. Functions like strlen() and sizeof() return a &lt;span style="font-style:italic;"&gt;size_t&lt;/span&gt;, and functions like memcpy(), memset(), or malloc() take a &lt;span style="font-style:italic;"&gt;size_t&lt;/span&gt; as one of their arguments.&lt;br /&gt;&lt;br /&gt;Let me show you a quick program to illustrate a point.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;#include &amp;lt;cstdio.h&amp;gt;&lt;br /&gt;&lt;br /&gt;#define O(x) printf(#x": %zu\n", sizeof(x))&lt;br /&gt;int main()&lt;br /&gt;{&lt;br /&gt;  O(signed char);&lt;br /&gt;  O(signed short);&lt;br /&gt;  O(signed int);&lt;br /&gt;  O(signed long);&lt;br /&gt;  O(signed long long);&lt;br /&gt;  O(signed);&lt;br /&gt;  O(unsigned char);&lt;br /&gt;  O(unsigned short);&lt;br /&gt;  O(unsigned int);&lt;br /&gt;  O(unsigned long);&lt;br /&gt;  O(unsigned long long);&lt;br /&gt;  O(unsigned);&lt;br /&gt;  O(size_t);&lt;br /&gt;  O(void *);&lt;br /&gt;  O(float);&lt;br /&gt;  O(double);&lt;br /&gt;  O(long double);&lt;br /&gt;  return(0);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;On a 32 bit system of mine, the output is as follows:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;signed char: 1&lt;br /&gt;signed short: 2&lt;br /&gt;signed int: 4&lt;br /&gt;signed long: 4&lt;br /&gt;signed long long: 8&lt;br /&gt;signed: 4&lt;br /&gt;unsigned char: 1&lt;br /&gt;unsigned short: 2&lt;br /&gt;unsigned int: 4&lt;br /&gt;unsigned long: 4&lt;br /&gt;unsigned long long: 8&lt;br /&gt;unsigned: 4&lt;br /&gt;size_t: 4&lt;br /&gt;void *: 4&lt;br /&gt;float: 4&lt;br /&gt;double: 8&lt;br /&gt;long double: 12&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;On a 64 bit system of mine, the output is as follows:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;signed char: 1&lt;br /&gt;signed short: 2&lt;br /&gt;signed int: 4&lt;br /&gt;signed long: 8&lt;br /&gt;signed long long: 8&lt;br /&gt;signed: 4&lt;br /&gt;unsigned char: 1&lt;br /&gt;unsigned short: 2&lt;br /&gt;unsigned int: 4&lt;br /&gt;unsigned long: 8&lt;br /&gt;unsigned long long: 8&lt;br /&gt;unsigned: 4&lt;br /&gt;size_t: 8&lt;br /&gt;void *: 8&lt;br /&gt;float: 4&lt;br /&gt;double: 8&lt;br /&gt;long double: 16&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Now notice for 32 bit, the &lt;span style="font-style:italic;"&gt;void *&lt;/span&gt; type is 4 bytes, and on 64 bit, it is 8 bytes. This means that a &lt;span style="font-style:italic;"&gt;void *&lt;/span&gt; can address any position in memory that the system is able to. In order to specify the amount, you'll notice in each case the &lt;span style="font-style:italic;"&gt;sizeof(size_t)&lt;/span&gt; matches the &lt;span style="font-style:italic;"&gt;sizeof(void *)&lt;/span&gt;. If I were to get a 128 bit system which had a &lt;span style="font-style:italic;"&gt;void *&lt;/span&gt; of 16 bytes, the &lt;span style="font-style:italic;"&gt;size_t&lt;/span&gt; would also be at least 16 bytes.&lt;br /&gt;&lt;br /&gt;There are other types which also matched the size of the &lt;span style="font-style:italic;"&gt;void *&lt;/span&gt; each time around, but if you look at my earlier explanation of the relationship of the various C types, you'll notice those other types are too variable to know if they'll be good for an amount of every system you try to use your application or library on, so always stick with the &lt;span style="font-style:italic;"&gt;size_t&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;All too often I see programmers use an &lt;span style="font-style:italic;"&gt;int&lt;/span&gt; for such an amount which is clearly wrong, or an &lt;span style="font-style:italic;"&gt;unsigned int&lt;/span&gt;, which is better, but also wrong, especially on my 64 bit system. Some programmers I also see use the type of just &lt;span style="font-style:italic;"&gt;unsigned&lt;/span&gt; by itself. I don't know who thought that up, but it's identical to an &lt;span style="font-style:italic;"&gt;unsigned int&lt;/span&gt;, which is also clearly wrong. I included &lt;span style="font-style:italic;"&gt;unsigned&lt;/span&gt; and &lt;span style="font-style:italic;"&gt;signed&lt;/span&gt; specifically in my test above because some people are under the mistaken notion that those types become as large as possible. Every time I see code which contains one of them, I want to vomit.&lt;br /&gt;&lt;br /&gt;If you ever have any doubt as to what size a type may be on your system, or get into an argument with someone, test things yourself with a &lt;span style="font-style:italic;"&gt;sizeof()&lt;/span&gt; call, it's not hard to do, or point them to this article.&lt;br /&gt;&lt;br /&gt;Now go out there and write some good libraries. I have too much vomit and bile on the floor here from all the horrible code I have to work with or review.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/833174317742362874-4615312562166259836?l=insanecoding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://insanecoding.blogspot.com/feeds/4615312562166259836/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=833174317742362874&amp;postID=4615312562166259836' title='22 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/833174317742362874/posts/default/4615312562166259836'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/833174317742362874/posts/default/4615312562166259836'/><link rel='alternate' type='text/html' href='http://insanecoding.blogspot.com/2010/03/does-anyone-understand-types-and.html' title='Does anyone understand types and magnitudes?'/><author><name>insane coder</name><uri>http://www.blogger.com/profile/06901386115570670209</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>22</thr:total></entry><entry><id>tag:blogger.com,1999:blog-833174317742362874.post-7802354735006886139</id><published>2010-03-11T17:56:00.000-08:00</published><updated>2010-03-11T19:46:27.879-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='parameters'/><category scheme='http://www.blogger.com/atom/ns#' term='recursion'/><category scheme='http://www.blogger.com/atom/ns#' term='GCC'/><category scheme='http://www.blogger.com/atom/ns#' term='C++-201x'/><category scheme='http://www.blogger.com/atom/ns#' term='variadic templates'/><category scheme='http://www.blogger.com/atom/ns#' term='C++-0x'/><category scheme='http://www.blogger.com/atom/ns#' term='language'/><title type='text'>C++-201x Variadic Templates</title><content type='html'>C++-201x (or C++-0x as near sighted individuals like to call it) introduced a new feature called variadic templates, which allows a template class or function to recieve multiple parameters to it of various types as you would normally achieve with "...".&lt;br /&gt;&lt;br /&gt;You could continue to use stdarg if you wish, but a limitation of it is that you have no way of knowing what type each parameter is to use with va_arg(), unless you just hard code it to only work with a specific type, or pass a type list how the printf() family of functions do it, or something similar.&lt;br /&gt;&lt;br /&gt;I always wanted a way to do func(integer, string, float, whatever), and interchange that with func(float, whatever, char), and now you can.&lt;br /&gt;&lt;br /&gt;If you try to research this topic online, basically everyone is just writing and talking about how to implement a tuple class, or how to make a type safe printf. Lets try something a little more interesting and perhaps instructive, yet simple.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;#include &amp;lt;iostream&amp;gt;&lt;br /&gt;using namespace std;&lt;br /&gt;&lt;br /&gt;//Output function to output any type without type specifiers like printf() family&lt;br /&gt;template &amp;lt;typename T, typename ...P&amp;gt;&lt;br /&gt;void output(T t, P ...p)&lt;br /&gt;{&lt;br /&gt;  cout &amp;lt;&amp;lt; t &amp;lt;&amp;lt; ' ';&lt;br /&gt;  if (sizeof...(p)) { output(p...); }&lt;br /&gt;  else { cout &amp;lt;&amp;lt; '\n'; }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;//Since variadic templates are recursive, must have a base case&lt;br /&gt;void output() { cout &amp;lt;&amp;lt; '\n'; }&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;//Compute sum of all parameters&lt;br /&gt;template &amp;lt;typename T, typename ...P&amp;gt;&lt;br /&gt;T sum(T t, P ...p)&lt;br /&gt;{&lt;br /&gt;  if (sizeof...(p))&lt;br /&gt;  {&lt;br /&gt;    t += sum(p...);&lt;br /&gt;  }&lt;br /&gt;  return(t);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;//Since variadic templates are recursive, must have a base case&lt;br /&gt;template &amp;lt;typename T&amp;gt;&lt;br /&gt;T sum(T t) { return(t); }&lt;br /&gt;&lt;br /&gt;//Test it&lt;br /&gt;int main()&lt;br /&gt;{&lt;br /&gt;  output();&lt;br /&gt;  output('5');&lt;br /&gt;  output('5', 2);&lt;br /&gt;  output('5', 2, "cows");&lt;br /&gt;  output('5', 2, "cows", -1);&lt;br /&gt;  output('5', 2, "cows", -1, 0.5f);&lt;br /&gt;  output('5', 2, "cows", -1, 0.5f, 16.3);&lt;br /&gt;&lt;br /&gt;  cout &amp;lt;&amp;lt; endl;&lt;br /&gt;&lt;br /&gt;  cout &amp;lt;&amp;lt; sum(1) &amp;lt;&amp;lt; '\n'&lt;br /&gt;       &amp;lt;&amp;lt; sum(1, 2) &amp;lt;&amp;lt; '\n'&lt;br /&gt;       &amp;lt;&amp;lt; sum(1, 2, 3) &amp;lt;&amp;lt; '\n'&lt;br /&gt;       &amp;lt;&amp;lt; sum(1, 2, 3, 4) &amp;lt;&amp;lt; '\n'&lt;br /&gt;       &amp;lt;&amp;lt; sum(1, 2, 3, 4, 5) &amp;lt;&amp;lt; '\n';&lt;br /&gt;&lt;br /&gt;  cout &amp;lt;&amp;lt; endl;&lt;br /&gt;&lt;br /&gt;  cout &amp;lt;&amp;lt; sum(0.1) &amp;lt;&amp;lt; '\n'&lt;br /&gt;       &amp;lt;&amp;lt; sum(0.1, 0.2) &amp;lt;&amp;lt; '\n'&lt;br /&gt;       &amp;lt;&amp;lt; sum(0.1, 0.2, 0.3) &amp;lt;&amp;lt; '\n';&lt;br /&gt;&lt;br /&gt;  cout &amp;lt;&amp;lt; endl;&lt;br /&gt;&lt;br /&gt;  return(0);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Here's how to compile and what the output looks like:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;/tmp&gt; g++-4.4 -Wall -o test test.cpp -std=gnu++0x&lt;br /&gt;/tmp&gt; ./test&lt;br /&gt;&lt;br /&gt;5&lt;br /&gt;5 2&lt;br /&gt;5 2 cows&lt;br /&gt;5 2 cows -1&lt;br /&gt;5 2 cows -1 0.5&lt;br /&gt;5 2 cows -1 0.5 16.3&lt;br /&gt;&lt;br /&gt;1&lt;br /&gt;3&lt;br /&gt;6&lt;br /&gt;10&lt;br /&gt;15&lt;br /&gt;&lt;br /&gt;0.1&lt;br /&gt;0.3&lt;br /&gt;0.6&lt;br /&gt;&lt;br /&gt;/tmp&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;As can be seen I achieved my desired goals of being able to pass various types, not know the types to be passed in advance, and not need a type list passed anywhere. All the other examples I've seen seem to be forgetting these important points.&lt;br /&gt;&lt;br /&gt;As for how this works "typename ...P" defines a template type of P which will be many parameters packed into a single variable. "P ...p" receives all these parameters in a variable named  "p".&lt;br /&gt;&lt;br /&gt;However the only things I can really do is see how many parameters are in "p" using "sizeof...(p)", or split "p" up into all its parameters, to then pass to a function by using "p...". It would be nice to be able to simply iterate through the values of "p", but that's not possible at the moment.&lt;br /&gt;&lt;br /&gt;Using standard recursion techniques, you can pass the split up parameters from "p" to a function which has enough templated parameters as "p" is currently holding, or a lesser amount, and the last parameter can be a variadic parameter to catch all the others which don't fit into the first few. Then using those first parameters, you can access the values you need, and so on ad infinitum.&lt;br /&gt;&lt;br /&gt;Read up on recursion if you're confused.&lt;br /&gt;&lt;br /&gt;Now if you're still wondering what this may be useful for, just consider functions which handle data serialization or something similar.&lt;br /&gt;&lt;br /&gt;One thing to note, at least with GCC at the moment, you always need to have a separate function as a base case, even if it's never used.&lt;br /&gt;&lt;br /&gt;Take "output('5', 2, "cows", -1, 0.5f, 16.3);", on the last leg of iteration, when the double is passed to the first parameter to be received by "t", and "p" is empty, "if (sizeof...(p)) { output(p...); }" which is the line responsible for the recursion seeing an empty "p" won't ask for "output()", but it seems the compiler still wants it to exist:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;test.cpp: In function ‘void output(T, P ...) [with T = double, P = ]’:&lt;br /&gt;test.cpp:8:   instantiated from ‘void output(T, P ...) [with T = float, P = double]’&lt;br /&gt;test.cpp:8:   instantiated from ‘void output(T, P ...) [with T = int, P = float, double]’&lt;br /&gt;test.cpp:8:   instantiated from ‘void output(T, P ...) [with T = const char*, P = int, float, double]’&lt;br /&gt;test.cpp:8:   instantiated from ‘void output(T, P ...) [with T = int, P = const char*, int, float, double]’&lt;br /&gt;test.cpp:8:   instantiated from ‘void output(T, P ...) [with T = char, P = int, const char*, int, float, double]’&lt;br /&gt;test.cpp:33:   instantiated from here&lt;br /&gt;test.cpp:8: error: no matching function for call to ‘output()’&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;I'm not sure though if this is required by the standard, or a bug in GCC.&lt;br /&gt;&lt;br /&gt;As for C++-201x support in general, GCC seems to be the furthest ahead, even surpassing Comeau C++.&lt;br /&gt;&lt;br /&gt;See a &lt;a href="http://wiki.apache.org/stdcxx/C++0xCompilerSupport"&gt;comparison of the various compilers' support of C++-201x&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/833174317742362874-7802354735006886139?l=insanecoding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://insanecoding.blogspot.com/feeds/7802354735006886139/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=833174317742362874&amp;postID=7802354735006886139' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/833174317742362874/posts/default/7802354735006886139'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/833174317742362874/posts/default/7802354735006886139'/><link rel='alternate' type='text/html' href='http://insanecoding.blogspot.com/2010/03/c-201x-variadic-templates.html' title='C++-201x Variadic Templates'/><author><name>insane coder</name><uri>http://www.blogger.com/profile/06901386115570670209</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-833174317742362874.post-6719862338908223167</id><published>2009-12-21T04:31:00.000-08:00</published><updated>2009-12-21T05:29:30.821-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Political Correctness'/><category scheme='http://www.blogger.com/atom/ns#' term='Antisemitism'/><category scheme='http://www.blogger.com/atom/ns#' term='Google'/><category scheme='http://www.blogger.com/atom/ns#' term='discrimination'/><title type='text'>Happy "Holidays" From Google</title><content type='html'>If you use GMail, you probably got this message recently:&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;Happy Holidays from Google    &lt;br /&gt;       &lt;br /&gt;Hello,&lt;br /&gt;&lt;br /&gt;As we near the end of the year, we wanted to take a moment to thank you for the time, energy, commitment, and trust you've shared with us in 2009.&lt;br /&gt;&lt;br /&gt;With sharing in mind, this year we've decided to do something a little different. We hope you'll find it fits the spirit of the holiday season.&lt;br /&gt;&lt;br /&gt;We're looking forward to working with you to build lasting success in 2010.&lt;br /&gt;&lt;br /&gt;Happy Holidays,&lt;br /&gt;Your Google Team&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;While on the surface it seems like a nice gesture, wouldn't it be nice if these big companies actually put some thought into what they wrote?&lt;br /&gt;&lt;br /&gt;The use of terms or "codewords" like "Happy Holidays" or "holiday season" is meant to be all inclusive of the various winter holidays celebrated by different religions or cultural groups, without singling out any one of them in particular. It's primarily meant to include minorities that celebrate &lt;a href="http://en.wikipedia.org/wiki/Kwanzaa"&gt;Kwanzaa&lt;/a&gt; and &lt;a href="http://en.wikipedia.org/wiki/Hanukkah"&gt;Hanukkah&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;But this letter was sent on December 21, after Hanukkah was already completed two days earlier. If they really wanted to be all inclusive, perhaps they should have sent it the first week in December, instead of waiting till soon after Hanukkah was over, portraying &lt;a href="http://en.wikipedia.org/wiki/Antisemitism"&gt;Antisemitism&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;All these "codewords" used are actually born out of "&lt;a href="http://en.wikipedia.org/wiki/Political_correctness"&gt;Political Correctness&lt;/a&gt;", a practice designed to discriminate against your average white male, while not actually caring about the minorities you're trying to protect. Isn't it nice to see another big company show that they aim for Political Correctness, yet show they couldn't care less about those minorities?&lt;br /&gt;&lt;br /&gt;On a similar note, a friend of mine tells me that he recently applied for a job at Google, and they sent him a form asking him to specify his &lt;a href="http://en.wikipedia.org/wiki/Race_(classification_of_human_beings)"&gt;Race&lt;/a&gt; on it. Wonder why?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/833174317742362874-6719862338908223167?l=insanecoding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://insanecoding.blogspot.com/feeds/6719862338908223167/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=833174317742362874&amp;postID=6719862338908223167' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/833174317742362874/posts/default/6719862338908223167'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/833174317742362874/posts/default/6719862338908223167'/><link rel='alternate' type='text/html' href='http://insanecoding.blogspot.com/2009/12/happy-holidays-from-google.html' title='Happy &quot;Holidays&quot; From Google'/><author><name>insane coder</name><uri>http://www.blogger.com/profile/06901386115570670209</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-833174317742362874.post-3214238975534194642</id><published>2009-12-05T12:17:00.001-08:00</published><updated>2009-12-05T12:35:33.617-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='pure failure'/><category scheme='http://www.blogger.com/atom/ns#' term='distribution'/><title type='text'>Cryptic Linux Distro Updates</title><content type='html'>We're almost in 2010, I thought by now to anyone who basically knows how to use a computer, general upgrade prompts in Linux Distros would make sense, and won't seem cryptic like "Abort, Retry, Ignore, Fail?".&lt;br /&gt;&lt;br /&gt;Then you get something like this:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_vLES3KKBdaM/SxrBGC_BaFI/AAAAAAAAAHE/1EIozvZrcgQ/s1600-h/wth.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 224px;" src="http://2.bp.blogspot.com/_vLES3KKBdaM/SxrBGC_BaFI/AAAAAAAAAHE/1EIozvZrcgQ/s320/wth.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5411850211863652434" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;This is a new upgrade message in Debian/Ubuntu.&lt;br /&gt;Here's the full text:&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;Various snmp software needs extracted MIBs from RFCs and IANA - which cannot be shipped - to be working as expected. These MIBs can be automatically fetched and extracted as part of installing this package.&lt;br /&gt; &lt;br /&gt;This will take several minutes to complete, even with a fast internet connection.&lt;br /&gt;&lt;br /&gt;Download and extract MIBs from RFCs and IANA? &lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;Are all these acronyms really necessary? Should a user even be given such cryptic information, and instead see a prompt along the lines of: "This package requires additional components to fully function, download them?".&lt;br /&gt;&lt;br /&gt;Even a power user who is familiar with a term like RFC, does this message even make any sense?&lt;br /&gt;&lt;br /&gt;Seems like Linux Distros still has a long way to go.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/833174317742362874-3214238975534194642?l=insanecoding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://insanecoding.blogspot.com/feeds/3214238975534194642/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=833174317742362874&amp;postID=3214238975534194642' title='8 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/833174317742362874/posts/default/3214238975534194642'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/833174317742362874/posts/default/3214238975534194642'/><link rel='alternate' type='text/html' href='http://insanecoding.blogspot.com/2009/12/crytpic-linux-distro-updates.html' title='Cryptic Linux Distro Updates'/><author><name>insane coder</name><uri>http://www.blogger.com/profile/06901386115570670209</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_vLES3KKBdaM/SxrBGC_BaFI/AAAAAAAAAHE/1EIozvZrcgQ/s72-c/wth.png' height='72' width='72'/><thr:total>8</thr:total></entry><entry><id>tag:blogger.com,1999:blog-833174317742362874.post-7208394244318228627</id><published>2009-11-24T09:24:00.000-08:00</published><updated>2009-11-26T09:54:43.767-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='bugs'/><category scheme='http://www.blogger.com/atom/ns#' term='HTTP'/><category scheme='http://www.blogger.com/atom/ns#' term='bad code'/><category scheme='http://www.blogger.com/atom/ns#' term='PHB'/><category scheme='http://www.blogger.com/atom/ns#' term='secure'/><category scheme='http://www.blogger.com/atom/ns#' term='Qt'/><category scheme='http://www.blogger.com/atom/ns#' term='apache'/><category scheme='http://www.blogger.com/atom/ns#' term='protocols'/><title type='text'>Malicious hackers are not out there</title><content type='html'>Security as it is today is an illusion. What? How could I say that, I'm not serious, am I?&lt;br /&gt;&lt;br /&gt;Most people today do not understand what security is or is not about. As evidenced by so many works of modern fiction centering around a plot where the terrorists/foreign government/aliens "bug" a server, a cable, or a satellite. Today's technology is supposed to prevent attacks involving any layer in the middle being bugged. Besides not understanding what modern security is capable of, many who are working with it do not understand what it is not capable of.&lt;br /&gt;&lt;br /&gt;A quick scan of source code in many projects will turn up code which fails even text book level security principals. I even see some major projects have code commented that it needs a more secure hash or nonce generator or something similar, which again could be found in modern textbooks.&lt;br /&gt;&lt;br /&gt;It is shocking the sheer number of online services or applications one can install (forums, webmail, blog, wiki, etc...) that have insecure login. Nearly all of them take user login credentials in plain text, allowing anyone between the user's computer and the website's application to steal the passwords.&lt;br /&gt;&lt;br /&gt;It is sad that nearly all sites use a custom login scheme that can be buggy and/or receive login credentials unencrypted, considering that &lt;a href="http://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol"&gt;HTTP&lt;/a&gt; - the protocol level of communication supports secure logins. HTTP login is rarely used though because it lacks a simple way to log out (why?), and can not be made to look pretty without using &lt;a href="http://en.wikipedia.org/wiki/Ajax_(programming)"&gt;AJAX&lt;/a&gt;, which is why the vast majority of site creators avoid it.  &lt;br /&gt;&lt;br /&gt;The HTTP specifications actually describes two methods of login for "&lt;i&gt;HTTP 401&lt;/i&gt;", one called "&lt;i&gt;&lt;a href="http://en.wikipedia.org/wiki/Basic_access_authentication"&gt;Basic Authentication&lt;/a&gt;&lt;/i&gt;", and another called "&lt;i&gt;&lt;a href="http://en.wikipedia.org/wiki/Digest_access_authentication"&gt;Digest Authentication&lt;/a&gt;&lt;/i&gt;". The former transmits login credentials in plain text, and the latter using an encryption of sorts. Most sites that avoid the worry of properly creating a custom login scheme and resort to HTTP 401 generally use Basic Authentication. Historically the reason is that most developers of HTTP servers and clients have been too &lt;b&gt;stupid&lt;/b&gt; to figure out how to do it properly. Which is surprising considering it is such a simple scheme. IIS and IE didn't have it done properly till relatively recently. Apache historically has had issues with it. Qt's network classes handled it improperly until recently. I'm also told Google Chrome currently has some issues with it.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;However, even if one used Digest as the login mechanism on their website, it can easily be subject to a &lt;br /&gt;&lt;a href="http://en.wikipedia.org/wiki/Man-in-the-middle_attack"&gt;Man in the middle attack&lt;/a&gt;, because the HTTP spec allows for there to be the possibility of sending passwords in an unencrypted fashion.&lt;br /&gt;&lt;br /&gt;The following diagram illustrates it:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_vLES3KKBdaM/SwwXvXgGGzI/AAAAAAAAAG0/ukXR9RoDnc8/s1600/backandforth1.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 159px;" src="http://2.bp.blogspot.com/_vLES3KKBdaM/SwwXvXgGGzI/AAAAAAAAAG0/ukXR9RoDnc8/s320/backandforth1.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5407723355095046962" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Since requests for authentication are requested from the server and not the client, the machine in the middle can change the request to be the insecure variant.&lt;br /&gt;&lt;br /&gt;So of course the next level up is &lt;a href="http://en.wikipedia.org/wiki/HTTP_Secure"&gt;HTTPS&lt;/a&gt;, which does HTTP over &lt;a href="http://en.wikipedia.org/wiki/Transport_Layer_Security"&gt;SSL/TLS&lt;/a&gt;, which is supposed to provide end to end security, preventing man in the middle attacks. This level of security makes all those fiction stories fail in their plot. It also is supposed to keep us safe, and is used by websites for processing credit card information and other sensitive material.&lt;br /&gt;&lt;br /&gt;However, most users just type "something.muffin" into their browser, instead of prefixing it with http:// or https://, which will default to http://. Which again means the server has to initiate the secure connection. Since again this is also over a system which has both secure and insecure methods of communication, the same type of man in the middle attack as above can be performed.&lt;br /&gt;&lt;br /&gt;The following diagram illustrates it:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_vLES3KKBdaM/SwwXvuMRpCI/AAAAAAAAAG8/ZM190luw1kQ/s1600/backandforth2.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 296px;" src="http://2.bp.blogspot.com/_vLES3KKBdaM/SwwXvuMRpCI/AAAAAAAAAG8/ZM190luw1kQ/s320/backandforth2.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5407723361185932322" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Webservers are generally the one that initiates the redirection to an HTTPS page, which can be modified by the server in the middle. Any &lt;a href="http://en.wikipedia.org/wiki/Uniform_Resource_Locator"&gt;URL&lt;/a&gt; within a page which begins with https:// can be rewritten. For example, https://something.muffin can be changed to http://something.muffin:443 by an attacker in the middle, and then proceed with the attack as described above.&lt;br /&gt;&lt;br /&gt;Of course users should be looking for padlocks and green labels and similar in their browser, but how many do so? Since most sites people visit aren't running in secure environments, do you expect them to really notice when some page which is supposed to be secure isn't? Do you expect users to be savvy about security when most developers aren't?&lt;br /&gt;&lt;br /&gt;The amount of data which should be transferred securely but isn't is mind boggling. I see websites create a security token over HTTPS, but then pass that token around over HTTP, allowing anyone in the middle to steal it. I see people e-mail each other passwords to accounts on machines they manage all the time. I see database administrators login to phpMyAdmin running on servers with their root passwords sent in plain text. People working on projects together frequently send each other login credentials over forums or IRC in plain text.&lt;br /&gt;&lt;br /&gt;Anyone managing a hub somewhere on the vast internet should be able to log tons and tons of passwords. Once a password is gotten to someone's e-mail or forum account, then that can be scanned for even more passwords. Also, I see many users save root/admin passwords in plain text files on web servers, if one managed to get into their account by nabbing their password to it, they quite often will also be able to gain root by a simple scan of the user's files. Even if not, once access is gained to a machine, &lt;a href="http://en.wikipedia.org/wiki/Privilege_escalation"&gt;privilege escalation&lt;/a&gt; is usually the norm as opposed to the exception, because server administrators quite often do not keep up with security updates, or are afraid to alter a server that they finally got working.&lt;br /&gt;&lt;br /&gt;Careful pondering would show our entire infrastructure for communication is really a house of cards. It wouldn't be that hard for a small team with a bit of capital to setup free proxy servers around the world, offer free wi-fi at a bunch of hotspots, or start a small ISP. So the question we have to ask ourselves, is why are we still standing with everything in the shaky state it's in? I think the answer is simple, the malicious hackers really aren't out there. Sure there's hackers out there, and some of them do wreak a bit of havoc. But it seems no one is really interested in making trouble on a large scale.&lt;br /&gt;&lt;br /&gt;Mostly the hackers you hear about are people in a competition, or research, or those "security hackers", which have gone legit and want to help you secure your business. It's funny the amount of times I heard a story about how some bigwig at a company goes to some sort of computer expo, and runs across a table or booth of security "gurus". The bigwig asks how the security gurus can help his business, with the response asking if the bigwig owns a website. Once the bigwig mentions the name of his site, one guru pulls out his laptop and shows the bigwig the site with it defaced in some way. The bigwig panics and immediately hires them to do a whole load of nothing. Little does he realize he was just man-in-the-middle'd.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/833174317742362874-7208394244318228627?l=insanecoding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://insanecoding.blogspot.com/feeds/7208394244318228627/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=833174317742362874&amp;postID=7208394244318228627' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/833174317742362874/posts/default/7208394244318228627'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/833174317742362874/posts/default/7208394244318228627'/><link rel='alternate' type='text/html' href='http://insanecoding.blogspot.com/2009/11/malicious-hackers-are-not-out-there.html' title='Malicious hackers are not out there'/><author><name>insane coder</name><uri>http://www.blogger.com/profile/06901386115570670209</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_vLES3KKBdaM/SwwXvXgGGzI/AAAAAAAAAG0/ukXR9RoDnc8/s72-c/backandforth1.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-833174317742362874.post-8661253099647708114</id><published>2009-11-10T15:35:00.001-08:00</published><updated>2009-11-10T16:39:29.736-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Library'/><category scheme='http://www.blogger.com/atom/ns#' term='torture'/><category scheme='http://www.blogger.com/atom/ns#' term='API'/><title type='text'>We got excellent documentation!</title><content type='html'>Ever try to work with a library you've never dealt with before? How do you approach the task? Do you try to find another program which uses the library and cannibalize it? Get someone who already knows how to use it to teach you? Find a good example? Or just trudge your way through and get something that barely works?&lt;br /&gt;&lt;br /&gt;I personally would like to have some good documentation which tells me exactly what I need to do to get the job done. Something which I can rely on to tell me everything I need to know, and to avoid any particular pitfalls.&lt;br /&gt;&lt;br /&gt;Except most of the time documentation is written by people who would be better off in some other profession. Like terrorist interrogators. Or perhaps the Spanish Inquisition.&lt;br /&gt;&lt;br /&gt;Although when you talk to people about the documentation for their library, they act like the documentation is two stone tablets brought down from heaven with sacred commandments written on them. Perhaps it is. But in the same fashion, the documentation is just as mysterious to anyone who hasn't spent years studying the library to decipher its true meaning.&lt;br /&gt;&lt;br /&gt;For many libraries, I have spent hours pouring over their documentation, to come up with like 5-10 lines of code to do what I needed to do. 10 hours for 10 lines of code? A bit much I think. Why can't people make documentation for those not familiar with the library, so they can get all the basic tasks done, and provide good reference for anything more advanced? Sometimes the documentation is so completely unhelpful, that I have to resort to the source code, or scour the internet for something to help me. This is completely unacceptable.&lt;br /&gt;&lt;br /&gt;Lets look at some of the various types of offenders.&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: center; font-weight: bold;"&gt;&lt;br /&gt;Doxygen equals documentation.&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;This is the kind of documentation written by those obnoxious programmers who don't want to write any documentation at all. They run a script on their source code which creates a set of HTML pages with a list of all the files in the library, a list of functions and classes, and all nicely interlinked. It also pulls out the comments about each function and clearly displays it. Sure it makes it easy to jump back and forth in a browser between various internals of the source. But it really gives no insight on how to use the library. If the library is written really cleanly, and commented well, perhaps this helps, but usually those creating the library didn't put any more effort into it than they put into creating their documentation.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: center; font-weight: bold;"&gt;Really, honest, there's documentation!&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;Then there are those that try to convince you they have documentation. You have a set of text files, or an HTML file, or a PDF or whatever which tells you how amazing the library is, and tells you all the wonderful things the library is capable of. They'll even give you notable examples of programs using their library. You'll have a great comparison chart of why this library is better than its competitors. You'll even get some design documentation, rational, and tips on how you can expand the library further. Good luck finding a single sentence which actually tells you how to use it.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: center; font-weight: bold;"&gt;We got you the bare essentials right over here, or was it over there?&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;Then you have the documentation which can never give you any complete idea. Sure, just use this function and pass it these six arrays all filled out. Don't worry about what to put in them, those arrays are explained on another page. Oh yeah this array can be used for a trillion different things, depending on which function you use it with, so we'll just enumerate what you may want to use it for. You may get more information looking at these data types though. Before you know it, you're looking at 20 different pages trying to figure out how to bring together the information to use a single function.&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: center; font-weight: bold;"&gt;I see your warrant, and I raise you a lawyer! &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;This kind of documentation seems to be written by those that don't actually want you to use their library and are all evasive about it. Every time you think the documentation is going to comply and actually tell you something useful, you're faced with something that isn't what you wanted. You'll get a bunch of small 4 line examples, each that do something, but no explanation as to what they're doing exactly. You'll even be told here and there some cryptic details about what a function supposedly does. Good luck figuring how to use anything.&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: center; font-weight: bold;"&gt;I see your lawyer, and I'll bury you with an army of lawyers!&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;This is one of the worst offenders that big companies or organizations generally pull. You'll get "complete working examples", and a lot of it. The examples will be thousands of lines long and perform a million other things besides what the library itself does, let alone the function you just looked up. Good luck finding what you need amidst all the noise. The Dietel &amp; Dietel line of how to program books that many colleges and universities use play the same game. Create enough information overload in the simplest of cases and force you to switch to a major in marketing.&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: center; font-weight: bold;"&gt;I'm sorry your honor, I didn't realize I didn't turn over the last chapter.&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;This kind of documentation isn't so bad. You'll get some good notes on how to do all the basic stuff the library is capable of. But any function or class with any sort of complexity is completely missing, and you'll have to refer to the source code. But I guess the authors don't know how to put the trickier things into words, at least not like the easier stuff.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;I think that about sums it up. There are some libraries out there with good documentation, but usually its of the kinds described above. Anyone else feel the same way?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/833174317742362874-8661253099647708114?l=insanecoding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://insanecoding.blogspot.com/feeds/8661253099647708114/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=833174317742362874&amp;postID=8661253099647708114' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/833174317742362874/posts/default/8661253099647708114'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/833174317742362874/posts/default/8661253099647708114'/><link rel='alternate' type='text/html' href='http://insanecoding.blogspot.com/2009/11/we-got-excellent-documentation.html' title='We got excellent documentation!'/><author><name>insane coder</name><uri>http://www.blogger.com/profile/06901386115570670209</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-833174317742362874.post-1420347785112323275</id><published>2009-11-06T03:16:00.000-08:00</published><updated>2009-11-06T03:52:02.049-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='GTK'/><category scheme='http://www.blogger.com/atom/ns#' term='x86-64'/><category scheme='http://www.blogger.com/atom/ns#' term='Library'/><category scheme='http://www.blogger.com/atom/ns#' term='distribution'/><category scheme='http://www.blogger.com/atom/ns#' term='insane ideas'/><category scheme='http://www.blogger.com/atom/ns#' term='closed source'/><category scheme='http://www.blogger.com/atom/ns#' term='KDE'/><category scheme='http://www.blogger.com/atom/ns#' term='CPU Detection'/><category scheme='http://www.blogger.com/atom/ns#' term='FatELF'/><category scheme='http://www.blogger.com/atom/ns#' term='binary'/><category scheme='http://www.blogger.com/atom/ns#' term='BSD'/><category scheme='http://www.blogger.com/atom/ns#' term='Qt'/><category scheme='http://www.blogger.com/atom/ns#' term='flash'/><category scheme='http://www.blogger.com/atom/ns#' term='Mac OS X'/><category scheme='http://www.blogger.com/atom/ns#' term='Portability'/><title type='text'>FatELF Dead?</title><content type='html'>A while back, someone came up with a project called &lt;a href="http://icculus.org/fatelf/"&gt;FatELF&lt;/a&gt;. I won't go into the exact details of all its trying to accomplish, but the basic idea was that like Mac OS X has &lt;a href="http://en.wikipedia.org/wiki/Universal_binary"&gt;universal binaries&lt;/a&gt; using the Mach-o object format which can run on multiple architectures, the same should be possible with software for Linux and FreeBSD, which use the &lt;a href="http://en.wikipedia.org/wiki/Executable_and_Linkable_Format"&gt;ELF&lt;/a&gt; object format.&lt;br /&gt;&lt;br /&gt;The creators of FatELF cite many different reasons why FatELF is a good idea, which most of us probably disagree with. But I found it could solve a pretty crucial issue today.&lt;br /&gt;&lt;br /&gt;The x86 line of processors which is what everyone uses for their home PCs recently switched from 32-bit to 64-bit. 64-bit x86 known as x86-64 is backwards compatible with the old architecture. However programs written for the new one generally run faster.&lt;br /&gt;&lt;br /&gt;x86-64 CPUs contain more registers than traditional x86-32 ones, so a CPU can juggle more data internally without offloading it to much slower RAM. Also, most distributions offered precompiled binaries designed for a very low common denominator, generally a 4x86 or the original Pentium. Programs compiled for these older processors can't take advantage of much of the improvements that have been done to the x86 line in the past 15 years. A distribution which targets the lowest common denominator for x86-64 on the other hand is targeting a much newer architecture, where every chip already contains &lt;a href="http://en.wikipedia.org/wiki/MMX_(instruction_set)"&gt;MMX&lt;/a&gt;, &lt;a href="http://en.wikipedia.org/wiki/Streaming_SIMD_Extensions"&gt;SSE&lt;/a&gt;, similar technologies, and other general enhancements.&lt;br /&gt;&lt;br /&gt;Installing a distribution geared for x86-64 can mean a much better computing experience for the most part. Except &lt;a href="http://www.zsnes.com"&gt;certain programs&lt;/a&gt; unfortunately are not yet 64 bit ready, or are closed source and can't be easily recompiled. In the past year or two, a lot of popular proprietary software were ported by their companies to x86-64, but some which are important for business fail completely under x86-64, such as Cisco's &lt;a href="http://www.webex.com/"&gt;Webex&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;x86-32 binaries can run on x86-64, provided all the libraries it needs are available on the system. However, many distributions don't provide x86-32 libraries on their x86-64 platform, or they provide only a couple, or provide ones which simply &lt;a href="https://bugs.launchpad.net/ubuntu/+source/ia32-libs/+bug/227475"&gt;don't work&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;All these issues could be fixed if FatELF was supported by the operating system. A distribution could provide an x86-64 platform, with all the major libraries containing both 32 and 64 bit versions within. Things like GTK, Qt, cURL, SDL, libao, OpenAL, and etc. We wouldn't have to worry about one of these &lt;a href="https://bugs.launchpad.net/ubuntu/+source/ia32-libs/+bug/227475"&gt;libraries conflicting when installing two variations&lt;/a&gt;, or simply missing from the system.&lt;br /&gt;&lt;br /&gt;It would make it easier on those on an x86-64 bit platform knowing they can run any binary they get elsewhere without a headache. It would also ease deployment issues for those that don't do anything special to take advantage of x86-64, and just want to pass out a single version of their software.&lt;br /&gt;&lt;br /&gt;I as a developer have to have an x86-32 &lt;a href="http://en.wikipedia.org/wiki/Chroot"&gt;chroot&lt;/a&gt; on all my development systems to make sure I can produce 32 bit binaries properly, which is also a hassle. All too often I have to jump back and forth between a 32 bit shell to compile the code, and a 64 bit shell where I have the rest of my software needed to analyze it, and commit it.&lt;br /&gt;&lt;br /&gt;But unfortunately, it now &lt;a href="http://icculus.org/cgi-bin/finger/finger.pl?user=icculus&amp;date=2009-11-03&amp;time=19-08-04"&gt;seems FatELF is dead&lt;/a&gt;, or on its way.&lt;br /&gt;&lt;br /&gt;I wish we could find a fully working solution to the 32 on 64 bit problem that crops up today.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/833174317742362874-1420347785112323275?l=insanecoding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://insanecoding.blogspot.com/feeds/1420347785112323275/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=833174317742362874&amp;postID=1420347785112323275' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/833174317742362874/posts/default/1420347785112323275'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/833174317742362874/posts/default/1420347785112323275'/><link rel='alternate' type='text/html' href='http://insanecoding.blogspot.com/2009/11/fatelf-dead.html' title='FatELF Dead?'/><author><name>insane coder</name><uri>http://www.blogger.com/profile/06901386115570670209</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-833174317742362874.post-4650004315148174784</id><published>2009-11-05T13:29:00.000-08:00</published><updated>2009-11-05T15:11:21.778-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='open source'/><category scheme='http://www.blogger.com/atom/ns#' term='good code'/><category scheme='http://www.blogger.com/atom/ns#' term='crazy executives'/><category scheme='http://www.blogger.com/atom/ns#' term='Library'/><category scheme='http://www.blogger.com/atom/ns#' term='bad code'/><category scheme='http://www.blogger.com/atom/ns#' term='PHB'/><category scheme='http://www.blogger.com/atom/ns#' term='language'/><category scheme='http://www.blogger.com/atom/ns#' term='Optimization'/><title type='text'>They actually want bad code</title><content type='html'>So I was in this huge meeting yesterday, and I got the shock of my life.&lt;br /&gt;&lt;br /&gt;We were discussing how we're going to go about creating and marketing a new program which will be deployed on the servers of our clients. When I suggested I be the one to take charge of the program design and creation, and handpick my team of the best programmers in the company to write the code, I was shot down. The reason? They don't want the program to be written correctly. They don't want the code written by people who know what they're doing.&lt;br /&gt;&lt;br /&gt;That had me completely flabbergasted. I needed more details. I asked what exactly was wrong with the way I did things? With creating the program properly? Our chief executive in charge of marketing dependability and quick maintenance boiled it down for me.&lt;br /&gt;&lt;br /&gt;The problems with me writing the code are as follows:&lt;br /&gt;No matter which language(s) we choose to build the program with, whether it be C++, PHP, C#, or something else, I'm going to make sure we use the classes and functions provided by the language most fit for use in our program. Every single function will be as clear and minimalistic and self contained as possible. And this is evil in terms of dependability and quick maintenance.&lt;br /&gt;&lt;br /&gt;If for example we used C# with .NET and I found just the perfect class out of the few thousand provided to fit the job, and it turns out down the line some issue crops up, apparently, they can't complain to Microsoft. Microsoft will tell them no one uses that class, and it is probably buggy, and they'll put it on a todo list to be looked at several months down the line.&lt;br /&gt;&lt;br /&gt;If I use any function or class in C++ or PHP outside of the most basic 10-20 ones that dime-a-dozen programmers learn right away, they won't be able to get someone outside our group of professionals to review and fix it.&lt;br /&gt;&lt;br /&gt;Basically, they want the program written only using classes, functions, arrays, loops, and the least amount of standard library usage. Because a random programmer most likely will barely be familiar with anything contained within the standard library.&lt;br /&gt;&lt;br /&gt;They would prefer reinventing built in functions, and also having them written incorrectly, in terms of output correctness, and running time. Since it means a programmer will never need to look in a manual to be able to understand a piece of code and fix it. Which is important apparently, as most can only figure out what is wrong with the logic directly in front of them, and then try to brute force correct output.&lt;br /&gt;&lt;br /&gt;But it doesn't even stop at good code making good use of the language, instead of reinventing the wheel.&lt;br /&gt;&lt;br /&gt;Quite often in our existing projects, I go to look at a bug report, and notice some function which works incorrectly, and in the process of fixing it, I condense the logic and make the code much better. Let me give an example.&lt;br /&gt;&lt;br /&gt;This is very similar to an existing case we had. The code was as follows:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;/*&lt;br /&gt;This function creates a log on Sunday, Tuesday, Thursday&lt;br /&gt;It takes as input an integer with a value of 1-7, 1 being Sunday.&lt;br /&gt;*/&lt;br /&gt;void logEveryOtherDay(int dayOfTheWeek)&lt;br /&gt;{&lt;br /&gt;  if (dayOfTheWeek == 1)&lt;br /&gt;  {&lt;br /&gt;    logger.open();&lt;br /&gt;    logger.write("Sunday");&lt;br /&gt;    logger.dumpData();&lt;br /&gt;    logger.close();&lt;br /&gt;  }&lt;br /&gt;  else if (dayOfTheWeek == 3)&lt;br /&gt;  {&lt;br /&gt;    logger.open();&lt;br /&gt;    logger.write("-------------");&lt;br /&gt;    logger.write("Tuesday");&lt;br /&gt;    logger.dumpData();&lt;br /&gt;    logger.close();&lt;br /&gt;  }&lt;br /&gt;  else if (dayOfTheWeek == 5)&lt;br /&gt;  {&lt;br /&gt;    logger.open();&lt;br /&gt;    logger.write("-------------");&lt;br /&gt;    logger.write("Thursday");&lt;br /&gt;    logger.dumpData();&lt;br /&gt;    logger.close();&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The problem reported was that logs from Sunday missed the ----- separator before it, and they'd want a log on Saturday too if ran then. When fixing it, the code annoyed me, and I quickly cleaned it to the following:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;//This functions takes an integer and returns true if it's odd, and false if even&lt;br /&gt;static bool isOdd(int i) { return(i&amp;amp;1); }&lt;br /&gt;&lt;br /&gt;static const char *daysOfTheWeek[] = {&lt;br /&gt;  0, //Begin with nothing, as we number the days of the week 1-7&lt;br /&gt;  "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;/*&lt;br /&gt;This function creates a log on Sunday, Tuesday, Thursday, Saturday&lt;br /&gt;It takes as input an integer with a value of 1-7, 1 being Sunday.&lt;br /&gt;*/&lt;br /&gt;void logEveryOtherDay(int dayOfTheWeek)&lt;br /&gt;{&lt;br /&gt;  if (isOdd(dayOfTheWeek)) //Logging isn't done on even days&lt;br /&gt;  {&lt;br /&gt;    logger.open();&lt;br /&gt;    logger.write("-------------");&lt;br /&gt;    logger.write(daysOfTheWeek(dayOfTheWeek));&lt;br /&gt;    logger.dumpData();&lt;br /&gt;    logger.close();&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;I think it should be obvious my code has much cleaner logic, and should be easy for any reasonable programmer to follow. I frequently do things like this. I even once went to look at a 2000 line function which had roughly a dozen bug reports against it, was a total mess, and ran really really slowly. Instead of hunting for the cause of each issue in it, I decided to scrap it. I created 2 helper functions, one 3 lines, the other 5, and rewrote the body of the function from 2000 lines to roughly 40. Instead of many nested ifs and several loops, we now had a single if and else which did exactly what they needed to, and called one of the two helper functions as needed where the real looping was done. The new function was profiled to run an order of a magnitude faster, and it passed all the test cases we designed, where the original failed a few. It now also contained 2 new features which were sorely lacking from the original. It was now also much easier to read it for correctness, as much less was going on in any section of the code.&lt;br /&gt;&lt;br /&gt;But as this executive continued to tell me, what I did on these occasions is evil for an average programmer.&lt;br /&gt;&lt;br /&gt;They can't comprehend a small amount of code doing so much. They can't understand what isOdd() does or is trying to do, unless they actually see its source. Its source of "return(i&amp;amp;1);" is just too confusing for them, because they don't know what "&amp;amp;1" means, nor can they comprehend how it can return true or false without containing an elaborate body of code. They can't just take the comment at face value that it does what it says it does. They are also frightened when they review different versions of a file to try to trace a bug when they see a ton of code just disappeared at some point, yet says it does more in the commit log.&lt;br /&gt;&lt;br /&gt;So to sum it up, they don't want me, or programmers like me working on any code that is to be deployed on a client's server. When a client from Africa, or South America calls us up with a problem, they don't want to fly one of our good programmers down there to look at it. They want to make sure they can hire someone on site in one of those places to go and look at the problem and fix it quickly. Which apparently can't happen when there's no guarantee of being able to hirer a good programmer there on short notice, and other kinds of programmers can't deal with good code or standard library/class usage.&lt;br /&gt;&lt;br /&gt;This mentality makes me very scared, although I guess it does explain to some extent why I find the innards of many rather large open source projects which are used commercially to be filled with tons of spaghetti logic, and written in a manner which suggests the author didn't really know what they were doing, nor should they be allowed to write code.&lt;br /&gt;&lt;br /&gt;Anyone experience anything similar? Comments?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/833174317742362874-4650004315148174784?l=insanecoding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://insanecoding.blogspot.com/feeds/4650004315148174784/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=833174317742362874&amp;postID=4650004315148174784' title='13 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/833174317742362874/posts/default/4650004315148174784'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/833174317742362874/posts/default/4650004315148174784'/><link rel='alternate' type='text/html' href='http://insanecoding.blogspot.com/2009/11/they-actually-want-bad-code.html' title='They actually want bad code'/><author><name>insane coder</name><uri>http://www.blogger.com/profile/06901386115570670209</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>13</thr:total></entry><entry><id>tag:blogger.com,1999:blog-833174317742362874.post-6119293578263555157</id><published>2009-10-28T07:09:00.000-07:00</published><updated>2009-10-28T12:03:02.279-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='torture'/><category scheme='http://www.blogger.com/atom/ns#' term='Television'/><category scheme='http://www.blogger.com/atom/ns#' term='protocols'/><title type='text'>Who still watches Television?</title><content type='html'>So I know a couple of people who every night or so, sit down and watch Television. I find the very thought of it mind boggling. Why would anyone torture h[im/er]self so?&lt;br /&gt;&lt;br /&gt;Television is all about locking yourself into someone else's timetable.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Each show comes on when your network decides it comes on.&lt;/li&gt;&lt;li&gt;You can't go back in case you missed something.&lt;/li&gt;&lt;li&gt;You can't rewatch a particular enjoyable scene.&lt;/li&gt;&lt;li&gt;You can't pause.&lt;/li&gt;&lt;li&gt;You can't stop it and continue it later.&lt;/li&gt;&lt;li&gt;You can't skip an annoying scene.&lt;/li&gt;&lt;/ul&gt;I find the idea of such a lack of control on the viewer's part excruciatingly painful.&lt;br /&gt;&lt;br /&gt;People miss appointments or go to bed late because they just had to know what happens. Parents have to fight with their kids to get them to do homework, which would make them miss their favorite show.&lt;br /&gt;&lt;br /&gt;People don't take proper care of themselves by not going to use the facilities when they need to, or getting a drink, or answering the phone. The list of problems goes on and on.&lt;br /&gt;&lt;br /&gt;This problem was always apparent, and many people bought video cassette recorders, or other newer devices to get the same job done. But there were those that didn't, and instead preferred to torture themselves.&lt;br /&gt;&lt;br /&gt;Okay, at first the technology may have been annoying (video cassettes), then it was too expensive. It's always another annoying peripheral in your house for the most part just taking up space. But why is this still going on today?&lt;br /&gt;&lt;br /&gt;If you read this site often, it's quite likely you own your own computer at home and have a high speed internet connection. There's also a good chance if you bought a computer or new hard drive in the past few years, that you have gigabytes of free space that you have no idea what to do with.&lt;br /&gt;&lt;br /&gt;If you own what I described above, why would you want to torture yourself so? Many stations are now putting their shows on their website which you can watch in mid-quality annoying flash. But ignoring that, nowadays, there are tons of people who record the show and then share that recording via Bit Torrent or file sharing websites.&lt;br /&gt;&lt;br /&gt;Unlike traditional home recording techniques, quite often you don't even have to program your device when to record for you anymore - when using a computer. Many "Online Television" sites provide RSS feeds that you can subscribe to which would automatically download your favorite shows as each episode comes out. You don't have to screw up setting to record at 3:59, and finding out your time was three minutes behind the network, and you missed the beginning. Or instead of setting the end time to 5:01, you screwed up and selected 4:01, and recorded a grand total of two minutes of your hour long show.&lt;br /&gt;&lt;br /&gt;These sites generally have the shows up a couple of minutes after they air in the earliest timezone showing them, and the files are of good quality, yet small enough to be downloaded in just a couple of minutes. If you happen to live in a later timezone, many times you can be finished watching a show before it even airs where you live.&lt;br /&gt;&lt;br /&gt;So who exactly is still torturing themselves? And why?&lt;br /&gt;&lt;br /&gt;Before you question, what would happen if everyone only started watching "Online Television", who exactly would be doing the recordings? We have to ask ourselves why aren't the companies producing these shows using the new medium available to distribute them? If they had an RSS feed with all the new shows set up to be downloaded via Bit Torrent on them (advertisements included), I'm sure many people would subscribe to them. They could even charge a few bucks a year to gain access to a private torrent, cutting out the middlemen (networks, cable companies) they use.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/833174317742362874-6119293578263555157?l=insanecoding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://insanecoding.blogspot.com/feeds/6119293578263555157/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=833174317742362874&amp;postID=6119293578263555157' title='7 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/833174317742362874/posts/default/6119293578263555157'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/833174317742362874/posts/default/6119293578263555157'/><link rel='alternate' type='text/html' href='http://insanecoding.blogspot.com/2009/10/who-still-watches-television.html' title='Who still watches Television?'/><author><name>insane coder</name><uri>http://www.blogger.com/profile/06901386115570670209</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-833174317742362874.post-4504079998605648002</id><published>2009-10-25T10:19:00.000-07:00</published><updated>2009-10-28T07:49:16.457-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Mozilla'/><category scheme='http://www.blogger.com/atom/ns#' term='HTTP'/><category scheme='http://www.blogger.com/atom/ns#' term='lighttpd'/><category scheme='http://www.blogger.com/atom/ns#' term='distribution'/><category scheme='http://www.blogger.com/atom/ns#' term='insane ideas'/><category scheme='http://www.blogger.com/atom/ns#' term='apache'/><category scheme='http://www.blogger.com/atom/ns#' term='protocols'/><category scheme='http://www.blogger.com/atom/ns#' term='Optimization'/><category scheme='http://www.blogger.com/atom/ns#' term='Firefox'/><title type='text'>Distributed HTTP</title><content type='html'>A couple years back, a friend of mine got into an area of research which was rather novel and interesting at the time. He created a website he hosted from his own computer, where one can read about the research, and download various data samples he made.&lt;br /&gt;&lt;br /&gt;Fairly soon, it was apparent that he couldn't host any large data samples. So he found the best compression software available, and setup a BitTorrent tracker on his computer. When someone downloaded some data samples, they would be sharing the bandwidth load, allowing more interested parties to download at once without crushing my friend's connection. This was back at a time when BitTorrent was unheard of, but those interested in getting the data would make the effort to do so.&lt;br /&gt;&lt;br /&gt;As time went on, his site popularity grew. He installed some forum software on his PC, so a community could begin discussing his findings. He also gave other people login credentials to his machine, so they can edit pages, and upload their own data.&lt;br /&gt;&lt;br /&gt;The site evolved into something close to a wiki, where each project got its own set of pages describing it, and what was currently known on the topic. Each project got some images to visually provide an idea of what each data set covered before one downloaded the torrent file. Some experiments also started to include videos.&lt;br /&gt;&lt;br /&gt;As the hits to his site kept increasing, my friend could no longer host his site on his own machine, and had to move his site to a commercial server which required payment on a monthly or yearly basis. While BitTorrent could cover the large data sets, it in no way provided a solution to hosting the various HTML pages and PNG images.&lt;br /&gt;&lt;br /&gt;The site constantly gained popularity, and my friend was forced to keep upgrading to an increasingly more powerful server, where the hosting costs increased just as rapidly. Requests for donations, and ads on the server could only help offset costs to an extent.&lt;br /&gt;&lt;br /&gt;I imagine other people and small communities have at times run into similar problems. I think its time for a solution to be proposed.&lt;br /&gt;&lt;br /&gt;Every major browser today caches files for each site it visits, so it doesn't have to rerequest the same images, scripts, and styles on each page, and conditionally requests pages, only if they haven't been updated since what was in the cache. I think this already solves one third of the problem.&lt;br /&gt;&lt;br /&gt;A new URI scheme can be created, perhaps &lt;i&gt;dhttp://&lt;/i&gt; that would act just like normal HTTP with a couple of exceptions. The browser would have some configurable options for Distributed HTTP, such as up to how many MB per site will it cache, how many MB overall, how many simultaneous uploads will it be willing to provide per site, as well as overall, which port it will run on, and a duration as to how long it will do so. When the browser connects via dhttp://, it'll include some extra headers providing the user's desired settings on this matter. The HTTP server will be modified to keep track of which IP addresses connected to it, and downloaded which files recently.&lt;br /&gt;&lt;br /&gt;When a request for a file comes into the DHTTP server, it can respond with a list of perhaps five IP addresses to choose from (if available), chosen based on an algorithm designed to round robin the available browsers connecting to the site, and the preferences chosen therein. The browser can then request via a normal HTTP request the same file from one of those IP addresses it received. The browser would need a miniature HTTP server built in which would understand that requests coming to it that seem to be for a DHTTP server should be replied to from its cache. It would also know not to share files that are in the cache which did not originate from a DHTTP server.&lt;br /&gt;&lt;br /&gt;If requests to each of those IP addresses have timed out, or responded with 404, then the browser can rerequest that file from the DHTTP server set with a timeout or unavailable header for each of those IP addresses, in which case the DHTTP server will respond with the requested file directly.&lt;br /&gt;&lt;br /&gt;The HTTP server should also know to keep track of when files are updated, so it knows not to refer a visitor to an IP address which contains an old file. This forwarding concept should also be disabled in cases of private data (login information), or dynamic pages. However for static (or dynamic which is only generated periodically) public data, all requests should be satisfiable by this described method.&lt;br /&gt;&lt;br /&gt;Thought would have to be put into how to handle "leach" browsers which never share from their cache, or just always request from the DHTTP server with timeout or unavailable headers sent.&lt;br /&gt;&lt;br /&gt;I think something implemented along these lines can help those smaller communities that host sites on their own machines, and would like to remain self hosting, or would like to alleviate hosting costs on commercial servers.&lt;br /&gt;&lt;br /&gt;Thoughts?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/833174317742362874-4504079998605648002?l=insanecoding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://insanecoding.blogspot.com/feeds/4504079998605648002/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=833174317742362874&amp;postID=4504079998605648002' title='11 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/833174317742362874/posts/default/4504079998605648002'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/833174317742362874/posts/default/4504079998605648002'/><link rel='alternate' type='text/html' href='http://insanecoding.blogspot.com/2009/10/distributed-http.html' title='Distributed HTTP'/><author><name>insane coder</name><uri>http://www.blogger.com/profile/06901386115570670209</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>11</thr:total></entry><entry><id>tag:blogger.com,1999:blog-833174317742362874.post-2975955068608254199</id><published>2009-10-23T05:52:00.001-07:00</published><updated>2009-10-23T06:30:07.074-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Blogger'/><category scheme='http://www.blogger.com/atom/ns#' term='API'/><category scheme='http://www.blogger.com/atom/ns#' term='searching'/><category scheme='http://www.blogger.com/atom/ns#' term='Google'/><title type='text'>Blogger Spam</title><content type='html'>If you remember, the &lt;a href="http://insanecoding.blogspot.com/2009/10/why-online-services-suck.html"&gt;other day&lt;/a&gt; I had a bit of a meltdown in terms of all the spam I saw piling up over here.&lt;br /&gt;&lt;br /&gt;I only have ~30 articles here, yet I had over 300 comments which were spam, and it is quite an annoying task to go delete them one by one. Especially when a week later, I'll have to go delete them one by one yet again.&lt;br /&gt;&lt;br /&gt;Instead of just throwing my hands up in the air, I found it was time to get insane - I went to check out Blogger's API. So looking it over, I found it's really easy to log in, and about everything else after that gets annoying.&lt;br /&gt;&lt;br /&gt;Blogger provides a way to get a list of articles, create new articles, delete articles, and also managing their comments. But the support is kind of limited if you want to specify what kind of data you want to retrieve.&lt;br /&gt;&lt;br /&gt;At first, I thought about analyzing each comment for spam, but I didn't want to run the risk of false positives, and figured my best bet for now is just to identify spammers. I identified 25 different spam accounts.&lt;br /&gt;&lt;br /&gt;However, Blogger only offers deleting comments by the comment ID, and then, only one by one. The only way to retrieve the comment ID is to retrieve the comments for a particular article, which includes the comments themselves and a bunch of other data. All this data is in a rather large XML file.&lt;br /&gt;&lt;br /&gt;It would be rather easy to delete comments if Blogger provided a function like deleteCommentsOf(userId, blogId), or getCommentIdsOf(userId, blogId), or something similar. But no, one needs 4 steps just to get an XML file which contains the comments IDs along with a lot of other unnecessary data. This has to be repeated for each article.&lt;br /&gt;&lt;br /&gt;It seems Blogger's API is really only geared towards providing various types of news feeds of a blog, and minimal remote management to allow others to create an interface for one to interact with blogger on a basic level. Nothing Blogger provides is geared towards en masse management.&lt;br /&gt;&lt;br /&gt;Blogger also has the nice undocumented caveat that when retrieving a list of articles for a site, it includes all draft articles not published yet, if the requester is currently logged in.&lt;br /&gt;&lt;br /&gt;But no matter, I create APIs wrapped around network requests and parsing data for a living. So using the libraries I created and use at work for this kind of thing, and 200 lines later which includes plenty of comments and whitespace, I got an API which allows me to delete all comments from a particular user from a Blogger site. So I arm an application using my new API with the 25 users I identified, and a few minutes later, presto, they're all gone.&lt;br /&gt;&lt;br /&gt;As of the time of this posting, there should be no spam in any of the articles here. I will have to rerun my application periodically, as well as update it with the user IDs of new spam accounts, but it shouldn't be a big deal any more.&lt;br /&gt;&lt;br /&gt;Remember the old programming dictum: Annoyance+Laziness = Great Software. It surely beats deleting things by hand every couple of days.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/833174317742362874-2975955068608254199?l=insanecoding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://insanecoding.blogspot.com/feeds/2975955068608254199/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=833174317742362874&amp;postID=2975955068608254199' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/833174317742362874/posts/default/2975955068608254199'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/833174317742362874/posts/default/2975955068608254199'/><link rel='alternate' type='text/html' href='http://insanecoding.blogspot.com/2009/10/blogger-spam.html' title='Blogger Spam'/><author><name>insane coder</name><uri>http://www.blogger.com/profile/06901386115570670209</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-833174317742362874.post-2727442416354096485</id><published>2009-10-19T08:39:00.000-07:00</published><updated>2009-10-19T09:50:34.439-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Mozilla'/><category scheme='http://www.blogger.com/atom/ns#' term='Blogger'/><category scheme='http://www.blogger.com/atom/ns#' term='Windows'/><category scheme='http://www.blogger.com/atom/ns#' term='Google'/><category scheme='http://www.blogger.com/atom/ns#' term='language'/><title type='text'>Why online services suck</title><content type='html'>Does anyone other than me think online services suck?&lt;br /&gt;&lt;br /&gt;The thing that annoys me the most is language settings. Online service designers one day had this great idea to check the geographical IP address the user visited their site from, and use it to automatically set the language to the native one for the country they visited from. While this sounds nice in theory, most people only know their mother tongue, and also go on vacation now and then, or visit some other country for business purposes.&lt;br /&gt;&lt;br /&gt;So here I am, on business in a foreign country, and I connect my laptop into the Ethernet jack in my hotel room which comes with free Internet access, so I can check my e-mail. What's the first thing I notice? The entire interface is no longer in English. Even worse is that the various menu items and buttons are moved around in this other language.&lt;br /&gt;&lt;br /&gt;Even Google, known for being ahead of the curve when it comes to web services can't help but make the same mistakes. I'm sitting here looking at the menu on top of Blogger, wondering which one is login.&lt;br /&gt;&lt;br /&gt;For Google this is a worse offense compared to other service providers, as I already was logged into their main site.&lt;br /&gt;&lt;br /&gt;Google keeps their cookies set for all eternity (well, until the next time rollover disaster), and they know I always used Google in English. Now it sees me connecting from a different country than usual and thinks I want my language settings switched? Even after I set it to English on their main page, I have to figure out how to set it to English again on Blogger and YouTube?&lt;br /&gt;&lt;br /&gt;What's really sad about all this is that every web browser sends each website as part of its request a "user agent", which tells the web server the name of the browser, a version number, operating system details, and &lt;span style="font-weight: bold; font-style: italic;"&gt;language&lt;/span&gt; information. My browser is currently sending: "Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.0.11)". Notice the en-US? That tells the site the browser is in English, for the United States. If I downloaded a different version of Firefox, or installed a language package and switched Firefox to a different language, it would tell the web server that I did so. If one uses Windows in another language, Internet Explorer will also tell the web server the language Windows/Internet Explorer is in.&lt;br /&gt;&lt;br /&gt;Why are these service providers ignoring browser information, and instead solely looking at geographical information? People travel all the times these days. Let us also not forget those in restrictive countries who use foreign proxy servers to access the internet.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;However, common issues, such as annoying language support is hardly the end of the problems. In terms of online communication, virtually all of them suffer from variations of spam. Again, where is Google here? Every time I go read comments on Blogger, I see nothing but spam posts. Even when I go to cleanup my own site, the spam just fills up again a few days later.&lt;br /&gt;&lt;br /&gt;Where's the flag as spam button? Where's the flag this user as solely a spammer button?&lt;br /&gt;&lt;br /&gt;Sure Google as a site manager lets me block all comments on my site till I personally review them to see if they're spam, but in today's need for hi-speed communication is that really an option when you may have a hot topic on hand? Why can't readers flag posts on their own?&lt;br /&gt;&lt;br /&gt;In terms of management, why doesn't Blogger's site management features include a list where I can check off posts and hit one mass delete, instead of having to click delete and "Yes I'm sure" on each and every spam post? Why can't I delete all posts from user X and ban that user from ever posting on my site again?&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Okay, maybe this isn't so much an article why online services suck, but more about language and spam complaints, and mostly at Google for the moment. Jet-lag, and getting your E-mail interface in Gibberish does wonders for a friendly post. I'll try to come up something better for my next article.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/833174317742362874-2727442416354096485?l=insanecoding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://insanecoding.blogspot.com/feeds/2727442416354096485/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=833174317742362874&amp;postID=2727442416354096485' title='11 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/833174317742362874/posts/default/2727442416354096485'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/833174317742362874/posts/default/2727442416354096485'/><link rel='alternate' type='text/html' href='http://insanecoding.blogspot.com/2009/10/why-online-services-suck.html' title='Why online services suck'/><author><name>insane coder</name><uri>http://www.blogger.com/profile/06901386115570670209</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>11</thr:total></entry><entry><id>tag:blogger.com,1999:blog-833174317742362874.post-8226247478694887160</id><published>2009-06-21T21:52:00.000-07:00</published><updated>2009-10-25T11:25:37.882-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='KDE'/><category scheme='http://www.blogger.com/atom/ns#' term='multicore'/><category scheme='http://www.blogger.com/atom/ns#' term='ALSA'/><category scheme='http://www.blogger.com/atom/ns#' term='GNOME'/><category scheme='http://www.blogger.com/atom/ns#' term='CPU Detection'/><category scheme='http://www.blogger.com/atom/ns#' term='multiseat'/><category scheme='http://www.blogger.com/atom/ns#' term='OSS'/><category scheme='http://www.blogger.com/atom/ns#' term='insane ideas'/><category scheme='http://www.blogger.com/atom/ns#' term='ManyMouse'/><title type='text'>How end users can utilize multicore processors</title><content type='html'>In recent years, the average desktop/workstation computer has gone from single core to multiple cores. Those of us who do video encoding, compression, or run a lot of processes at once are absolutely loving it. Where does everyone else fit in?&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;span style="font-weight: bold;"&gt;Why multiple cores?&lt;/span&gt;&lt;br /&gt;&lt;div style="text-align: left;"&gt;How many operations a particular CPU core could do at once has been increasing over the years. If we compare what we can do today with what were able to do a decade ago, we see we've come a long way. Our CPU cores were once doubling in speed every 18 months. However, in recent times, it seems trying to push the CPU farther and farther in how much it could do at once has been steadily getting closer and closer to the theoretical maximum. There's only so much we can do to make the various components that make up a CPU get closer together on the silicon, or work better together, with today's technology, and without making the chip catch fire. Therefore, we went to the next logical step, put more than one CPU on each CPU slab we stick in our motherboards.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;span style="font-weight: bold;"&gt;Are CPUs currently fast enough?&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;CPUs have gotten so fast in recent years, that for normal every day usage, they're fast enough. Whether I'm browsing the web, writing an e-mail, doing some math, painting a pretty picture, listening to music, watching a video, doing my taxes, or most other common tasks, nothing about the machine's speed disappoints me. I've found 2 GHz to be fast enough. Unlike the old days, I'm not sitting in front of a machine wishing it could go faster, or subconsciously reaching for my remote to hit the fast forward button while watching a program load or complete an operation. Of course increased memory availability played a role in this too. In any event, computers made in the past 5 years or so have been fast enough for most people.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;span style="font-weight: bold;"&gt;So what can multiple cores do for me?&lt;/span&gt;&lt;br /&gt;&lt;div style="text-align: left;"&gt;Well, for certain applications, where large processes can be broken up into other smaller independent processes, the processes can be completed faster. For video encoding, a video frame can be broken up into quadrants, each one handled individually. For compression, a file can be broken up into chunks, and each compressed separately. You can now also run a lot of processes at once. You can have an HTTP Server, an application server, and a database server all running on a single machine without any one of them slowing the others down. Even for home users, you can run more background processes, such as your virus scanner while you're working on other projects. For programmers like myself, it's great, I can compile multiple programs at once, or have a program compiling in the background, while still doing other stuff, such as burning a DVD, listening to music, and reading CNN, with everything being really fast and responsive, and without my DVD drive spitting out a coaster. Also, if you like running multiple operating systems at once using VirtualBox or something similar, you can assign each operating system you're currently using its own CPU.&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;span style="font-weight: bold;"&gt;So what can't multiple cores do?&lt;/span&gt;&lt;br /&gt;&lt;div style="text-align: left;"&gt;Multiple cores can't make single threaded applications work faster. If all you're doing is playing your average game, or writing a letter or something similar, you'll have one core being used to it's maximum, while the others are just sitting there doing nothing.&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;span style="font-weight: bold;"&gt;Why aren't more applications multi-threaded?&lt;/span&gt;&lt;br /&gt;&lt;div style="text-align: left;"&gt;This is simply a matter of there's nothing to do to make them multi-threaded. In a program where every single operation is based off of the result of the previous operation, there is no way to break it up into two components, to run each in a different thread, and by extension, each in a different CPU core. Even if there are a couple of occasional segments that can be broken up, in many cases it may not be worth the overhead of doing so. Multi-threading only works well when there's large segments each containing many operations in them that can be broken up. Multi-threading fails if the two threads have to constantly sync results between them.&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;span style="font-weight: bold;"&gt;So why should the average user bother for 4 or 8 core processors?&lt;/span&gt;&lt;br /&gt;&lt;div style="text-align: left;"&gt;This is an excellent question. Why should a business or average home user waste money on these higher end CPUs? Let me call your attention to a few other points about modern computers.&lt;br /&gt;&lt;br /&gt;Modern desktop computers even at home and work generally come with:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;6 audio jacks in the rear, 2 in the front&lt;/li&gt;&lt;li&gt;8 or more USB ports&lt;/li&gt;&lt;li&gt;A video card with two DVI connectors&lt;/li&gt;&lt;li&gt;A motherboard which supports 2 video cards&lt;/li&gt;&lt;/ul&gt;&lt;div style="text-align: left;"&gt;Now of course there's cases where you want 7.1 sound, and lots of microphones, and other devices plugged in, your cameras, gamepads, and printers (hey, printers belong attached to your network switch!), multiple screens, or lots of video cards working together on video like CPUs do in the cases similar to what I highlighted above.&lt;br /&gt;&lt;br /&gt;Now if you realize what you have, it all seems a little too convenient.&lt;br /&gt;4 cores - 4 users.&lt;br /&gt;8 audio jacks - Speakers + Microphone per user for 4 users.&lt;br /&gt;8 USB ports - Keyboard+Mouse per user for 4 users.&lt;br /&gt;2 video cards with 2 DVI each - 4 screens.&lt;br /&gt;&lt;br /&gt;It almost seems like the average machine you can buy for $500-$600 is asking you to use it for 4 users!&lt;br /&gt;&lt;br /&gt;Now the great thing is, even average integrated sound cards allow each jack to receive their own programming, and plugging something in one jack doesn't force mute another. On many models, even a jack's primary use of input/output is really left up to the software, and only the average drivers force it to be one or the other.&lt;br /&gt;&lt;br /&gt;You can buy extension cords to keep your "virtual" computers further away from each other. You can get powered USB hubs to provide as many USB ports you want to each user, or get keyboards which offer additional USB ports on them so users can plug in thier own devices such as memory sticks.&lt;br /&gt;&lt;br /&gt;Now look back at the average home user. Who at home with only a single computer doesn't get the wife or kids nagging they want to do something? Who at home or at work wouldn't like to cut costs a bit? You already are going to have to buy several screens, speakers, keyboards, and mice. Now just buy one computer, maybe spend $100-$200 on it more than you wanted to, and perhaps another $50 on extension cords, and now you don't have to buy another 1-3 computers, which would add on $400-$2000.&lt;br /&gt;&lt;br /&gt;Imagine even if you're a power user who does a lot of intensive projects that you need that really powerful computer for. How often are you really encoding those videos? Can you just have them queued up to be done at night while everyone is sleeping?&lt;br /&gt;&lt;br /&gt;You can now also spend a little extra on that processor and video card to keep your son happy playing all those new games, while you get a lot more power out of your computer during normal hours while he's doing homework, and you're doing your taxes, all on the same machine, and still end up saving money. You also now only have to run that virus scanner on a single machine in the background, instead of several.&lt;br /&gt;&lt;br /&gt;So now the question is, can we already do this? And how well can we do it?&lt;br /&gt;There's some &lt;a href="http://en.wikipedia.org/wiki/Multiseat_configuration"&gt;articles&lt;/a&gt; you can &lt;a href="http://wiki.x.org/wiki/Development/Documentation/Multiseat"&gt;read&lt;/a&gt;, on how to set it up, but it seems a lot more of a hassle than one would like.&lt;br /&gt;&lt;br /&gt;It'd be really nice to have a special multiseat optimized distro ready to be used in such a manner out of the box. Or perhaps a distro such as Ubuntu provided a special mode for it. Maybe even GNOME or KDE should have an admin setting where they can detect your current setup and offer an option turn the multiple virtual desktops they have on them into an environment suitable for multiple users with just a single click.&lt;br /&gt;&lt;br /&gt;Of course this would probably need a lot more work done in the sound area to provide a virtual sound system to each user, and make sure the underlying drivers can work with each audio jack independently. Also would mean they'd have to understand how to sandbox each particular virtual desktop now residing on each screen to the inputs in front of it.&lt;br /&gt;&lt;br /&gt;Thoughts?&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/833174317742362874-8226247478694887160?l=insanecoding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://insanecoding.blogspot.com/feeds/8226247478694887160/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=833174317742362874&amp;postID=8226247478694887160' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/833174317742362874/posts/default/8226247478694887160'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/833174317742362874/posts/default/8226247478694887160'/><link rel='alternate' type='text/html' href='http://insanecoding.blogspot.com/2009/06/how-to-utilize-multicore-processors.html' title='How end users can utilize multicore processors'/><author><name>insane coder</name><uri>http://www.blogger.com/profile/06901386115570670209</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-833174317742362874.post-615430563171174456</id><published>2009-06-18T20:29:00.000-07:00</published><updated>2009-06-20T20:03:31.071-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='GNOME'/><category scheme='http://www.blogger.com/atom/ns#' term='Library'/><category scheme='http://www.blogger.com/atom/ns#' term='Windows'/><category scheme='http://www.blogger.com/atom/ns#' term='closed source'/><category scheme='http://www.blogger.com/atom/ns#' term='KDE'/><category scheme='http://www.blogger.com/atom/ns#' term='open source'/><category scheme='http://www.blogger.com/atom/ns#' term='ALSA'/><category scheme='http://www.blogger.com/atom/ns#' term='API'/><category scheme='http://www.blogger.com/atom/ns#' term='OSS'/><category scheme='http://www.blogger.com/atom/ns#' term='BSD'/><category scheme='http://www.blogger.com/atom/ns#' term='flash'/><category scheme='http://www.blogger.com/atom/ns#' term='Mac OS X'/><category scheme='http://www.blogger.com/atom/ns#' term='Portability'/><title type='text'>State of sound in Linux not so sorry after all</title><content type='html'>About two years ago, I wrote an article titled the "&lt;a href="http://insanecoding.blogspot.com/2007/05/sorry-state-of-sound-in-linux.html"&gt;The Sorry State of Sound in Linux&lt;/a&gt;", hoping to get some sound issues in Linux fixed. Now two years later a lot has changed, and it's time to take another look at the state of sound in Linux today.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;A quick summary of the last article for those that didn't read it:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Sound in Linux has an interesting history, and historically lacked sound mixing on hardware that was more software based than hardware.&lt;/li&gt;&lt;li&gt;Many sound servers were created to solve the mixing issue.&lt;/li&gt;&lt;li&gt;Many libraries were created to solve multiple back-end issues.&lt;/li&gt;&lt;li&gt;ALSA replaced OSS version 3 in the Kernel source, attempting to fix existing issues.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;There was a closed source OSS update which was superb.&lt;/li&gt;&lt;li&gt;Linux distributions have been removing OSS support from applications in favor of ALSA.&lt;/li&gt;&lt;li&gt;Average sound developer prefers a simple API.&lt;/li&gt;&lt;li&gt;Portability is a good thing.&lt;/li&gt;&lt;li&gt;Users are having issues in certain scenarios.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;Now much has changed, namely:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;OSS is now free and open source once again.&lt;/li&gt;&lt;li&gt;PulseAudio has become widespread.&lt;/li&gt;&lt;li&gt;Existing libraries have been improved.&lt;/li&gt;&lt;li&gt;New Linux Distributions have been released, and some existing ones have attempted an overhaul of their entire sound stack to improve users' experience.&lt;/li&gt;&lt;li&gt;People read the last article, and have more knowledge than before, and in some cases, have become more opinionated than before.&lt;/li&gt;&lt;li&gt;I personally have looked much closer at the issue to provide even more relevant information.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;Let's take a closer look at the pros and cons of OSS and ALSA as they are, not five years ago, not last year, not last month, but as they are &lt;b&gt;today&lt;/b&gt;.&lt;br /&gt;&lt;br /&gt;First off, ALSA.&lt;br /&gt;ALSA consists of three components. First part is drivers in the Kernel with an API exposed for the other two components to communicate with. Second part is a sound developer API to allow developers to create programs which communicate with ALSA. Third part is a sound mixing component which can be placed between the other two to allow multiple programs using the ALSA API to output sound simultaneously.&lt;br /&gt;&lt;br /&gt;To help make sense of the above, here is a diagram:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_vLES3KKBdaM/SjsQ99zkDQI/AAAAAAAAAFk/MU8zZwXRZJY/s1600-h/alsa.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 310px; height: 320px;" src="http://1.bp.blogspot.com/_vLES3KKBdaM/SjsQ99zkDQI/AAAAAAAAAFk/MU8zZwXRZJY/s320/alsa.png" alt="" id="BLOGGER_PHOTO_ID_5348887639181495554" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Note, the diagrams presented in this article are made by myself, a very bad artist, and I don't plan to win any awards for them. Also they may not be 100% absolutely accurate down to the last detail, but accurate enough to give the average user an idea of what is going on behind the scenes.&lt;br /&gt;&lt;br /&gt;A sound developer who wishes to output sound in their application can take any of the following routes with ALSA:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Output using ALSA API directly to ALSA's Kernel API (when sound mixing is disabled)&lt;/li&gt;&lt;li&gt;Output using ALSA API to sound mixer, which outputs to ALSA's Kernel API (when sound mixing is enabled)&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Output using OSS version 3 API directly to ALSA's Kernel API&lt;/li&gt;&lt;li&gt;Output using a wrapper API which outputs using any of the above 3 methods&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;As can be seen, ALSA is quite flexible, has sound mixing which OSSv3 lacked, but still provides legacy OSSv3 support for older programs. It also offers the option of disabling sound mixing in cases where the sound mixing reduced quality in any way, or introduced latency which the end user may not want at a particular time.&lt;br /&gt;&lt;br /&gt;Two points should be clear, ALSA has optional sound mixing outside the Kernel, and the path ALSA's OSS legacy API takes lacks sound mixing.&lt;br /&gt;&lt;br /&gt;An obvious con should be seen here, ALSA which was initially designed to fix the sound mixing issue at a lower and more direct level than a sound server doesn't work for "older" programs.&lt;br /&gt;&lt;br /&gt;Obvious pros are that ALSA is free, open source, has sound mixing, can work with multiple sound cards (all of which OSS lacked during much of version 3's lifespan), and included as part of the Kernel source, and tries to cater to old and new programs alike.&lt;br /&gt;&lt;br /&gt;The less obvious cons are that ALSA is Linux only, it doesn't exist on FreeBSD or Solaris, or Mac OS X or Windows. Also, the average developer finds ALSA's native API too hard to work with, but that is debatable.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Now let's take a look at OSS today. OSS is currently at version 4, and is a completely different beast than OSSv3 was.&lt;br /&gt;Where OSSv3 went closed source, OSSv4 is open sourced today, under GPL, 3 clause BSD, and CDDL.&lt;br /&gt;While a decade old OSS was included in the Linux Kernel source, the new greatly improved OSSv4 is not, and thus may be a bit harder for the average user to try out. Older OSSv3 lacked sound mixing and support for multiple sound cards, OSSv4 does not. Most people who discuss OSS or try OSS to see how it stacks up against ALSA unfortunately are referring to, or are testing out the one that is a decade old, providing a distortion of the facts as they are today.&lt;br /&gt;&lt;br /&gt;Here's a diagram of OSSv4:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_vLES3KKBdaM/SjsQ-d_yg6I/AAAAAAAAAF0/JU4mG0IdV-s/s1600-h/oss.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 281px;" src="http://1.bp.blogspot.com/_vLES3KKBdaM/SjsQ-d_yg6I/AAAAAAAAAF0/JU4mG0IdV-s/s320/oss.png" alt="" id="BLOGGER_PHOTO_ID_5348887647822709666" border="0" /&gt;&lt;/a&gt;A sound developer wishing to output sound has the following routes on OSSv4:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Output using OSS API right into the Kernel with sound mixing&lt;/li&gt;&lt;li&gt;Output using ALSA API to the OSS API with sound mixing&lt;/li&gt;&lt;li&gt;Output using a wrapper API to any of the above methods&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;Unlike in ALSA, when using OSSv4, the end user &lt;b&gt;always&lt;/b&gt; has sound mixing. Also because sound mixing is running in the Kernel itself, it doesn't suffer from the latency ALSA generally has.&lt;br /&gt;&lt;br /&gt;Although OSSv4 does offer their own ALSA emulation layer, it's pretty bad, and I haven't found a single ALSA program which is able to output via it properly. However, this isn't an issue, since as mentioned above, ALSA's own sound developer API can output to OSS, providing perfect compatibility with ALSA applications today. You can read more about how to set that up in one of my &lt;a href="http://insanecoding.blogspot.com/2009/05/perfect-sound-with-oss-version-4.html"&gt;recent articles&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;ALSA's own library is able to do this, because it's actually structured as follows:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_vLES3KKBdaM/SjsQ-L2UVII/AAAAAAAAAFs/Vcm87Z3KMDw/s1600-h/alsalib.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 134px;" src="http://2.bp.blogspot.com/_vLES3KKBdaM/SjsQ-L2UVII/AAAAAAAAAFs/Vcm87Z3KMDw/s320/alsalib.png" alt="" id="BLOGGER_PHOTO_ID_5348887642951144578" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;As you can see, it can output to either OSS or ALSA Kernel back-ends (other back-ends too which will be discussed lower down).&lt;br /&gt;&lt;br /&gt;Since both OSS and ALSA based programs can use an OSS or ALSA Kernel back-end, the differences between the two are quite subtle (note, we're not discussing OSSv3 here), and boils down to what I know from research and testing, and is not immediately obvious.&lt;br /&gt;&lt;br /&gt;OSS always has sound mixing, ALSA does not.&lt;br /&gt;OSS sound mixing is of higher quality than ALSA's, due to OSS using more precise math in its sound mixing.&lt;br /&gt;OSS has less latency compared to ASLA when mixing sound due to everything running within the Linux Kernel.&lt;br /&gt;OSS offers per application volume control, ALSA does not.&lt;br /&gt;ALSA can have the Operating System go into suspend mode when sound was playing and come out of it with sound still playing, OSS on the other hand needs the application to restart sound.&lt;br /&gt;OSS is the only option for certain sound cards, as ALSA drivers for a particular card are either really bad or non existent.&lt;br /&gt;ALSA is the only option for certain sound cards, as OSS drivers for a particular card are either really bad or non existent.&lt;br /&gt;ALSA is included in Linux itself and is easy to get ahold of, OSS (v4) is not.&lt;br /&gt;&lt;br /&gt;Now the question is where does the average user fall in the above categories? If the user has a sound card which only works (well) with one or the other, then obviously they should use the one that works properly. Of course a user may want to try both to see if one performs better than the other one.&lt;br /&gt;&lt;br /&gt;If the user really needs to have a program output sound right until Linux goes into suspend mode, and then continues where it left off when resuming, then ALSA is (currently) the only option. I personally don't find this to be a problem, and furthermore I doubt it's a large percentage of users that even use suspend in Linux. Suspend in general in Linux isn't great, due to some rogue piece of hardware like a network or video card which screws it up.&lt;br /&gt;&lt;br /&gt;If the user doesn't want a hassle, ALSA also seems the obvious choice, as it's shipped directly with the Linux Kernel, so it's much easier for the user to use a modern ALSA than it is a modern OSS. However it should be up to the Linux Distribution to handle these situations, and to the end user, switching from one to the other should be seamless and transparent. More on this later.&lt;br /&gt;&lt;br /&gt;Yet we also see due to better sound mixing and latency when sound mixing is involved, that OSS is the better choice, as long as none of the above issues are present. But the better mixing is generally only noticed at higher volume levels, or rare cases, and latency as I'm referring to is generally only a problem if you play heavy duty games, and not a problem if you just want to listen to some music or watch a video.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;But wait this is all about the back-end, what about the whole developer API issue?&lt;br /&gt;&lt;br /&gt;Many people like to point fingers at the various APIs (I myself did too to some extent in my previous article). But they really don't get it. First off, this is how your average sound wrapper API works:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_vLES3KKBdaM/SjsRE0yUJXI/AAAAAAAAAGM/r56yGx3edww/s1600-h/wrapper.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 156px;" src="http://1.bp.blogspot.com/_vLES3KKBdaM/SjsRE0yUJXI/AAAAAAAAAGM/r56yGx3edww/s320/wrapper.png" alt="" id="BLOGGER_PHOTO_ID_5348887757019424114" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;The program outputs sound using a wrapper, such as OpenAL, SDL, or libao, and then sound goes to the appropriate high level or low level back-end, and the user doesn't have to worry about it.&lt;br /&gt;&lt;br /&gt;Since the back-ends can be various Operating Systems sound APIs, they allow a developer to write a program which has sound on Windows, Mac OS X, Linux, and more pretty easily.&lt;br /&gt;&lt;br /&gt;Some like &lt;a href="http://blogs.adobe.com/penguin.swf/2007/05/welcome_to_the_jungle.html"&gt;Adobe&lt;/a&gt; like to say how this is some kind of problem, and makes it impossible to output sound in Linux. Nothing could be further from the truth. &lt;a href="http://blogs.adobe.com/penguin.swf/linuxaudio.png"&gt;Graphs like these&lt;/a&gt; are very misleading. OpenAL, SDL, libao, GStreamer, NAS, Allegro, and more all exist on Windows too. I don't see anyone complaining there.&lt;br /&gt;&lt;br /&gt;I can make a similar diagram for Windows:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_vLES3KKBdaM/Sjsptq1kkCI/AAAAAAAAAGU/yITp1qKuHOU/s1600-h/windowsaudio.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 221px;" src="http://4.bp.blogspot.com/_vLES3KKBdaM/Sjsptq1kkCI/AAAAAAAAAGU/yITp1qKuHOU/s320/windowsaudio.png" alt="" id="BLOGGER_PHOTO_ID_5348914847002431522" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;This above diagram is by no means complete, as there's XAudio, other wrapper libs, and even some Windows only sound libraries which I've forgotten the name of.&lt;br /&gt;&lt;br /&gt;This by no means bothers anybody, and should not be made an issue.&lt;br /&gt;&lt;br /&gt;In terms of usage, the libraries stack up as follows:&lt;br /&gt;OpenAL - Powerful, tricky to use, great for "3D audio". I personally was able to get a lot done by following a couple of example and only spent an hour or two adding sound to an application.&lt;br /&gt;SDL - Simplistic, uses a callback API, decent if it fits your program design. I personally was able to add sound to an application in half an hour with SDL, although I don't think it fits every case load.&lt;br /&gt;libao - Very simplistic, incredibly easy to use, although problematic if you need your application to not do sound blocking. I added sound to a multitude of applications using libao in a matter of minutes. I just think it's a bit more annoying to do if you need to give your program its own sound thread, so again depends on the case load.&lt;br /&gt;&lt;br /&gt;I haven't played with the other sound wrappers, so I can't comment on them, but the same ideas are played out with each and every one.&lt;br /&gt;&lt;br /&gt;Then of course there's the actual OSS and ALSA APIs on Linux. Now why would anyone use them when there are lovely wrappers that are more portable, customized to match any particular case load? In the average case, this is in fact true, and there is no reason to use OSS or ALSA's API to output sound. In some cases, using a wrapper API can add latency which you may not want, and you don't need any of the advantages of using a wrapper API.&lt;br /&gt;&lt;br /&gt;Here's a breakdown of how OSS and ALSA's APIs stack up.&lt;br /&gt;OSSv3 - Easy to use, most developers I spoke to like it, exists on every UNIX but Mac OS X. I added sound to applications using OSSv3 in 10 minutes.&lt;br /&gt;OSSv4 - Mostly backwards compatible with v3, even easier to use, exists on every UNIX except Mac OS X and Linux when using the ALSA back-end, has sound re-sampling, and AC3 decoding out of the box. I added sound to several applications using OSSv4 in 10 minutes each.&lt;br /&gt;ALSA - Hard to use, most developers I spoke to dislike it, poorly documented, not available anywhere but Linux. Some developers however prefer it, as they feel it gives them more flexibility than the OSS API. I personally spent 3 hours trying to make heads or tails out of the documentation and add sound to an application. Then I found sound only worked on the machine I was developing on, and had to spend another hour going over the docs and tweaking my code to get it working on both machines I was testing on at the time. Finally, I released my application with the ALSA back-end, to find several people complaining about no sound, and started receiving patches from several developers. Many of those patches fixed sound on their machine, but broke sound on one of my machines. Here we are a year later, and my application after many hours wasted by several developers, ALSA now seems to output sound decently on all machines tested, but I sure don't trust it. We as developers don't need these kinds of issues. Of course, you're free to disagree, and even cite examples how you figured out the documentation, added sound quickly, and have it work flawlessly everywhere by everyone who tested your application. I must just be stupid.&lt;br /&gt;&lt;br /&gt;Now I &lt;a href="http://insanecoding.blogspot.com/2007/05/sorry-state-of-sound-in-linux.html"&gt;previously&lt;/a&gt; thought the OSS vs. ALSA API issue was significant to end users, in so far as what they're locked into, but really it only matters to developers. The main issue is though, if I want to take advantage of all the extra features that OSSv4's API has to offer (and I do), I have to use the OSS back-end. Users however don't have to care about this one, unless they use programs which take advantage of these features, which there are few of.&lt;br /&gt;&lt;br /&gt;However regarding wrapper APIs, I did find a few interesting results when testing them in a variety of programs.&lt;br /&gt;App -&gt; libao -&gt; OSS API -&gt; OSS Back-end - Good sound, low latency.&lt;br /&gt;App -&gt; libao -&gt; OSS API -&gt; ALSA Back-end - Good sound, minor latency.&lt;br /&gt;App -&gt; libao -&gt; ALSA API -&gt; OSS Back-end - Good sound, low latency.&lt;br /&gt;App -&gt; libao -&gt; ALSA API -&gt; ALSA Back-end - Bad sound, horrible latency.&lt;br /&gt;App -&gt; SDL -&gt; OSS API -&gt; OSS Back-end - Good sound, really low latency.&lt;br /&gt;App -&gt; SDL -&gt; OSS API -&gt; ALSA Back-end - Good sound, minor latency.&lt;br /&gt;App -&gt; SDL -&gt; ALSA API -&gt; OSS Back-end - Good sound, low latency.&lt;br /&gt;App -&gt; SDL -&gt; ALSA API -&gt; ALSA Back-end - Good sound, minor latency.&lt;br /&gt;App -&gt; OpenAL -&gt; OSS API -&gt; OSS Back-end - Great sound, really low latency.&lt;br /&gt;App -&gt; OpenAL -&gt; OSS API -&gt; ALSA Back-end - Adequate sound, bad latency.&lt;br /&gt;App -&gt; OpenAL -&gt; ALSA API -&gt; OSS Back-end - Bad sound, bad latency.&lt;br /&gt;App -&gt; OpenAL -&gt; ALSA API -&gt; ALSA Back-end - Adequate sound, bad latency.&lt;br /&gt;App -&gt; OSS API -&gt; OSS Back-end - Great sound, really low latency.&lt;br /&gt;App -&gt; OSS API -&gt; ALSA Back-end - Good sound, minor latency.&lt;br /&gt;App -&gt; ALSA API -&gt; OSS Back-end - Great sound, low latency.&lt;br /&gt;App -&gt; ALSA API -&gt; ALSA Back-end - Good sound, bad latency.&lt;br /&gt;&lt;br /&gt;If you're having a hard time trying to wrap your head around the above chart, here's a summary:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;OSS back-end always has good sound, except when using OpenAL-&gt;ALSA to output to it.&lt;/li&gt;&lt;li&gt;ALSA generally sounds better when using the OSS API, and has lower latency (generally because that avoids any sound mixing as per an earlier diagram).&lt;/li&gt;&lt;li&gt;OSS related technology is generally the way to go for best sound.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;But wait, where do sound servers fit in?&lt;br /&gt;&lt;br /&gt;Sounds servers were initially created to deal with problems caused by OSSv3 which currently are non existent, namely sound mixing. The sound server stack today looks something like this:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_vLES3KKBdaM/SjsQ-6rtvsI/AAAAAAAAAGE/ZRh1wkN1MAc/s1600-h/soundserver.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 242px; height: 320px;" src="http://2.bp.blogspot.com/_vLES3KKBdaM/SjsQ-6rtvsI/AAAAAAAAAGE/ZRh1wkN1MAc/s320/soundserver.png" alt="" id="BLOGGER_PHOTO_ID_5348887655523139266" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;As should be obvious, these sound servers today do nothing except add latency, and should be done away with. KDE 4 has moved away from the aRts sound server, and instead uses a wrapper API known as Phonon, which can deal with a variety of back-ends (which some in themselves can go through a particular sound server if need be).&lt;br /&gt;&lt;br /&gt;However as mentioned above, ALSA's mixing is not of the same high quality as OSS's is, and ALSA also lacks some nice features such as per application volume control.&lt;br /&gt;&lt;br /&gt;Now one could turn off ALSA's low quality mixer, or have an application do it's own volume control internally via modifying the sound wave its outputting, but these choices aren't friendly towards users or developers.&lt;br /&gt;&lt;br /&gt;Seeing this, Fedora and Ubuntu has both stepped in with a so called state of the art sound server known as PulseAudio.&lt;br /&gt;&lt;br /&gt;If you remember this:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_vLES3KKBdaM/SjsQ-L2UVII/AAAAAAAAAFs/Vcm87Z3KMDw/s1600-h/alsalib.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 134px;" src="http://2.bp.blogspot.com/_vLES3KKBdaM/SjsQ-L2UVII/AAAAAAAAAFs/Vcm87Z3KMDw/s320/alsalib.png" alt="" id="BLOGGER_PHOTO_ID_5348887642951144578" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;As you can see, ALSA's API can also output to PulseAudio, meaning programs written using ALSA's API can output to PulseAudio and use PulseAudio's higher quality sound mixer seamlessly without requiring the modification of old programs. PulseAudio is also able to send sound to another PulseAudio server on the network to output sound remotely. PulseAudio's stack is something like this:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_vLES3KKBdaM/SjsQ-mZzETI/AAAAAAAAAF8/iBdrRxsDycQ/s1600-h/pulse.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 234px; height: 320px;" src="http://3.bp.blogspot.com/_vLES3KKBdaM/SjsQ-mZzETI/AAAAAAAAAF8/iBdrRxsDycQ/s320/pulse.png" alt="" id="BLOGGER_PHOTO_ID_5348887650079281458" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;As you can see it looks very complex, and a 100% accurate breakdown of PulseAudio is even more complex.&lt;br /&gt;&lt;br /&gt;Thanks to PulseAudio being so advanced, most of the wrapper APIs can output to it, and Fedora and Ubuntu ship with all that set up for the end user, it can in some cases also receive sound written for another sound server such as ESD, without requiring ESD to run on top of it. It also means that many programs are now going through &lt;b&gt;many&lt;/b&gt; layers before they reach the sound card.&lt;br /&gt;&lt;br /&gt;Some have seen PulseAudio as the new Voodoo which is our new savior, sound written to any particular API can be output via it, and it has great mixing to boot.&lt;br /&gt;&lt;br /&gt;Except many users who play games for example are crying that this adds a &lt;b&gt;TREMENDOUS&lt;/b&gt; amount of latency, and is very noticeable even in not so high-end games. Users don't like hearing enemies explode a full 3 seconds after they saw the enemy explode on screen. Don't let anyone kid you, there's no way a sound server, especially with this level of bloat and complexity ever work with anything approaching low latency acceptable for games.&lt;br /&gt;&lt;br /&gt;Compare the insanity that is PulseAudio with this:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_vLES3KKBdaM/SjsQ-d_yg6I/AAAAAAAAAF0/JU4mG0IdV-s/s1600-h/oss.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 281px;" src="http://1.bp.blogspot.com/_vLES3KKBdaM/SjsQ-d_yg6I/AAAAAAAAAF0/JU4mG0IdV-s/s320/oss.png" alt="" id="BLOGGER_PHOTO_ID_5348887647822709666" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;Which do you think looks like a better sound stack, considering that their sound mixing, per application volume control, compatibility with applications, and other features are on par?&lt;br /&gt;&lt;br /&gt;And yes, lets not forget the applications. I'm frequently told about how some application is written to use a particular API, therefore either OSS or ALSA need to be the back-end they use. However as explained above, either API can be used on either back-end. If &lt;a href="http://insanecoding.blogspot.com/2009/05/perfect-sound-with-oss-version-4.html"&gt;setup right&lt;/a&gt;, you don't have to have a lack of sound using newer version of Flash when using the OSS back-end.&lt;br /&gt;&lt;br /&gt;So where are we today exactly?&lt;br /&gt;The biggest issues I find is that the Distributions simply aren't setup to make the &lt;i&gt;choice&lt;/i&gt; easy on the users. Debian and derivatives provide a Linux sound base package to select whether you want OSS or ALSA to be your back-end, except it really doesn't do anything. Here's what we do need from such a package:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;On selecting OSS, it should install the latest OSS package, as well as ALSA's ALSA API-&gt;OSS back-end interface, and set it up.&lt;/li&gt;&lt;li&gt;Minimally configure an installed OpenAL to use OSS back-end, and preferably SDL, libao, and other wrapper libraries as well.&lt;/li&gt;&lt;li&gt;Recognize the setting when installing a new application or wrapper library and configure that to use OSS as well.&lt;/li&gt;&lt;li&gt;Do all the above in reverse when selecting ALSA instead.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;Such a setup would allow users to easily switch between them if their sound card only worked with the one which wasn't the distribution's default. It would also easily allow users to objectively test which one works better for them if they care to, and desire to use the best possible setup they can. Users should be given this capability. I personally believe OSS is superior, but we should leave the choice up to the user if they don't like whichever is the system default.&lt;br /&gt;&lt;br /&gt;Now I repeatedly hear the claim: "But, but, OSS was taken out of the Linux Kernel source, it's never going to be merged back in!"&lt;br /&gt;&lt;br /&gt;Let's analyze that objectively. Does it matter what is included in the default Linux Kernel? Can we not use VirtualBox instead of KVM when KVM is part of the Linux Kernel and VirtualBox isn't? Can we not use KDE or GNOME when neither of them are part of the Linux Kernel?&lt;br /&gt;&lt;br /&gt;What matters in the end is what the distributions support, not what's built in. Who cares what's built in? The only difference is that the Kernel developers themselves won't maintain anything not officially part of the Kernel, but that's the precise jobs that the various distributions fill, ensuring their Kernel modules and related packages work shortly after each new Kernel comes out.&lt;br /&gt;&lt;br /&gt;Anyways, a few closing points.&lt;br /&gt;&lt;br /&gt;I believe OSS is the superior solution over ALSA, although your mileage may vary. It'd be nice if OSS and ALSA just shared &lt;b&gt;all&lt;/b&gt; their drivers, not having an issue where one has support for one sound card, but not the other.&lt;br /&gt;&lt;br /&gt;OSS should get suspend support and anything else it lacks in comparison to ALSA even if insignificant. Here's a hint, why doesn't Ubuntu hire the OSS author and get it more friendly in these last few cases for the end user? &lt;a href="http://4front-tech.com/hannublog/?p=23"&gt;He is currently looking for a job&lt;/a&gt;. Also throw some people at it to improve the existing volume controlling widgets to be friendlier with the new OSSv4, and maybe get stuff like HAL to recognize OSSv4 out of the box.&lt;br /&gt;&lt;br /&gt;Problems should be fixed directly, not in a roundabout matter as is done with PulseAudio, that garbage needs to go. If users need remote sound (and few do), one should just be easily able to map /dev/dsp over NFS, and output everything to OSS that way, achieving network transparency on the file level as UNIX was designed for (everything is a file), instead of all these non UNIX hacks in place today in regards to sound.&lt;br /&gt;&lt;br /&gt;The distributions really need to get their act together. Although in recent times &lt;a href="http://www.dracolinux.org/"&gt;Draco Linux&lt;/a&gt; has come out which is OSS only, and &lt;a href="http://www.archlinux.org/"&gt;Arch Linux&lt;/a&gt; seems to treat OSSv4 as a full fledged citizen to the end user, giving them choice, although I'm told they're both bad in the the ALSA compatibility department not setting it up properly for the end user, and in the case of Arch Linux, requiring the user to modify the config files of each application/library that uses sound.&lt;br /&gt;&lt;br /&gt;OSS is portable thanks to its OS abstraction API, being more relevant to the UNIX world as a whole, unlike ALSA. FreeBSD however uses their own take on OSS to avoid the abstraction API, but it's still mostly compatible, and one can install the official OSSv4 on FreeBSD if they so desire.&lt;br /&gt;&lt;br /&gt;Sound in Linux really doesn't have to be that sorry after all, the distributions just have to get their act together, and stop with all the finger pointing, propaganda, and FUD that is going around, which is only relevant to ancient versions of OSS, if not downright irrelevant or untrue. Let's stop the madness being perpetrated by the likes of Adobe, PulseAudio propaganda machine, and whoever else out there. Let's be objective and use the best solutions instead of settling for mediocrity or hack upon hack.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/833174317742362874-615430563171174456?l=insanecoding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://insanecoding.blogspot.com/feeds/615430563171174456/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=833174317742362874&amp;postID=615430563171174456' title='232 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/833174317742362874/posts/default/615430563171174456'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/833174317742362874/posts/default/615430563171174456'/><link rel='alternate' type='text/html' href='http://insanecoding.blogspot.com/2009/06/state-of-sound-in-linux-not-so-sorry.html' title='State of sound in Linux not so sorry after all'/><author><name>insane coder</name><uri>http://www.blogger.com/profile/06901386115570670209</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_vLES3KKBdaM/SjsQ99zkDQI/AAAAAAAAAFk/MU8zZwXRZJY/s72-c/alsa.png' height='72' width='72'/><thr:total>232</thr:total></entry><entry><id>tag:blogger.com,1999:blog-833174317742362874.post-8976052605205604947</id><published>2009-05-25T17:06:00.000-07:00</published><updated>2009-05-25T18:08:53.235-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ALSA'/><category scheme='http://www.blogger.com/atom/ns#' term='OSS'/><category scheme='http://www.blogger.com/atom/ns#' term='flash'/><category scheme='http://www.blogger.com/atom/ns#' term='Firefox'/><title type='text'>Perfect sound with OSS version 4</title><content type='html'>So I just happened to be keeping my eye on some packages being upgraded in Debian on dist-upgrade, and something caught my eye, the package "libasound2-plugins". I wondered what kind of plugins it provided, so I asked APT to show me what it was. Here's what came up:&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;Package: libasound2-plugins&lt;br /&gt;Priority: optional&lt;br /&gt;Section: libs&lt;br /&gt;Installed-Size: 488&lt;br /&gt;Maintainer: Debian ALSA Maintainers &lt;pkg-alsa-devel@lists.alioth.debian.org&gt;&lt;br /&gt;Architecture: amd64&lt;br /&gt;Source: alsa-plugins&lt;br /&gt;Version: 1.0.19-2&lt;br /&gt;Depends: libasound2 (&gt;&gt; 1.0.18), libc6 (&gt;= 2.2.5), libjack0 (&gt;= 0.116.1), libpulse0 (&gt;= 0.9.14), libsamplerate0&lt;br /&gt;Filename: pool/main/a/alsa-plugins/libasound2-plugins_1.0.19-2_amd64.deb&lt;br /&gt;Size: 119566&lt;br /&gt;MD5sum: 89efb281a3695d8c0f0d3c153ff8041a&lt;br /&gt;SHA1: fdd93b68ec0b8e6de0b67b3437b9f8c86c04b449&lt;br /&gt;SHA256: 7eb5b023373db00ca1b65765720a99654a0b63be741a5f5db2516a8881048aa6&lt;br /&gt;Description: ALSA library additional plugins&lt;br /&gt; This package contains plugins for the ALSA library that are&lt;br /&gt; not included in the main libasound2 package.&lt;br /&gt; .&lt;br /&gt; The following plugins are included, among other:&lt;br /&gt;   - a52: S16 to A52 stream converter&lt;br /&gt;   - jack: play or capture via JACK&lt;br /&gt;&lt;b&gt;   - oss: run native ALSA apps on OSS drivers&lt;/b&gt;&lt;br /&gt;   - pulse: play or capture via Pulse Audio&lt;br /&gt;   - lavcrate, samplerate and speexrate: rate converters&lt;br /&gt;   - upmix and vdownmix: convert from/to 2 and 4/6 channel streams&lt;br /&gt; .&lt;br /&gt; ALSA is the Advanced Linux Sound Architecture.&lt;br /&gt;Enhances: libasound2&lt;br /&gt;Homepage: http://www.alsa-project.org/&lt;br /&gt;Tag: devel::library, role::plugin, works-with::audio&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;Now something jumped out at me, run native ALSA apps on OSS drivers?&lt;br /&gt;If you read my &lt;a href="http://insanecoding.blogspot.com/2007/05/sorry-state-of-sound-in-linux.html"&gt;sound article&lt;/a&gt;, you know I'm an advocate of OSSv4, since it seems superior where it matters.&lt;br /&gt;&lt;br /&gt;So I looked into the documentation for the Debian (as well as Ubuntu) package "libasound2-plugins" on how this ALSA over OSS works exactly.&lt;br /&gt;&lt;br /&gt;I edited &lt;i&gt;/etc/asound.conf&lt;/i&gt;, and changed it to the following:&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;pcm.!default {&lt;br /&gt;        type oss&lt;br /&gt;        device /dev/dsp&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;ctl.!default {&lt;br /&gt;    type oss&lt;br /&gt;    device /dev/mixer&lt;br /&gt;}&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;And presto, every ALSA application now started properly outputting sound for me. No more need to always have to fiddle with configurations for each sound layer to use OSS, because the distros don't allow auto config of them.&lt;br /&gt;&lt;br /&gt;I could never get flash on 64 bit with sound before, even though each new OSS release says they "fixed it". Now it does work for me.&lt;br /&gt;&lt;br /&gt;I tested the following with ALSA:&lt;br /&gt;MPlayer (-ao alsa)&lt;br /&gt;Firefox, flashplugin-nonfree, &lt;a href="http://homestarrunner.com"&gt;Homestar Runner&lt;/a&gt;&lt;br /&gt;ZSNES (-ad alsa)&lt;br /&gt;bsnes (defaults)&lt;br /&gt;&lt;br /&gt;Oh and in case you're wondering, mixing is working perfectly. I tried running four instances of MPlayer, two set to use ALSA, the other two set to output using OSS, and I was able to hear all four at once.&lt;br /&gt;&lt;br /&gt;Now it's great to setup each application and sound layer individually to use OSS, so there's less overhead. But just making this one simple change means you don't have to for each application where the distro defaulted to ALSA, or have to suffer incompatibility when a particular application is ALSA only.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Note that depending how you installed OSS and which version, it may have tried forcing ALSA programs to use a buggy ALSA emulation library, which is incomplete, and not bug for bug compatible with the real ALSA. If that happened to you, here's how to use the real ALSA libraries, which are 100% ALSA compatible, as it's 100% the real ALSA.&lt;br /&gt;&lt;br /&gt;First check where everything is pointing with the following command &lt;i&gt;ls -la /usr/lib/libasound.*&lt;/i&gt;&lt;br /&gt;I get the following:&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;-rw-r--r-- 1 root root 1858002 2009-03-04 11:09 /usr/lib/libasound.a&lt;br /&gt;-rw-r--r-- 1 root root     840 2009-03-04 11:09 /usr/lib/libasound.la&lt;br /&gt;lrwxrwxrwx 1 root root      18 2009-03-06 03:35 /usr/lib/libasound.so -&gt; libasound.so.2.0.0&lt;br /&gt;lrwxrwxrwx 1 root root      18 2009-03-06 03:35 /usr/lib/libasound.so.2 -&gt; libasound.so.2.0.0&lt;br /&gt;-rw-r--r-- 1 root root  935272 2009-03-04 11:09 /usr/lib/libasound.so.2.0.0&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;Now as you can see libasound.so and libasound.so.2 both point to libasound.so.2.0.0. The bad emulation is called libsalsa. So if instead of seeing "-&gt; libasound..." you see "-&gt; libsalsa..." there, you'll want to correct the links.&lt;br /&gt;&lt;br /&gt;You can correct with the following commands as root:&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;cd /usr/lib/&lt;br /&gt;rm libasound.so libasound.so.2&lt;br /&gt;ln -s libasound.so.2.0.0 libasound.so&lt;br /&gt;ln -s libasound.so.2.0.0 libasound.so.2&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;If you're using Ubuntu and don't know how to switch to root, try &lt;i&gt;sudo su&lt;/i&gt; prior to the steps above.&lt;br /&gt;&lt;br /&gt;If you'd like to try to configure as many applications as possible to use OSS directly to avoid any unneeded overhead, see the documentation &lt;a href="http://www.opensound.com/wiki/index.php/Configuring_Applications_for_OSSv4"&gt;here&lt;/a&gt; and &lt;a href="http://wiki.archlinux.org/index.php/OSS"&gt;here&lt;/a&gt; which provide a lot of useful information. However if you're happy with your current setup, the hassle to configure each additional application isn't needed as long as you setup ALSA to use OSS.&lt;br /&gt;&lt;br /&gt;Enjoy your sound!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/833174317742362874-8976052605205604947?l=insanecoding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://insanecoding.blogspot.com/feeds/8976052605205604947/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=833174317742362874&amp;postID=8976052605205604947' title='31 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/833174317742362874/posts/default/8976052605205604947'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/833174317742362874/posts/default/8976052605205604947'/><link rel='alternate' type='text/html' href='http://insanecoding.blogspot.com/2009/05/perfect-sound-with-oss-version-4.html' title='Perfect sound with OSS version 4'/><author><name>insane coder</name><uri>http://www.blogger.com/profile/06901386115570670209</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>31</thr:total></entry><entry><id>tag:blogger.com,1999:blog-833174317742362874.post-239974731819219795</id><published>2009-05-25T01:31:00.000-07:00</published><updated>2009-05-25T01:41:17.904-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Ancient Coding Ideas'/><title type='text'>Ancient coding ideas finally in English - Part 2</title><content type='html'>&lt;ol&gt;&lt;br /&gt;&lt;li&gt;&lt;br /&gt;What is the best way to write it? Whatever is best for the program itself and best for the programmers.&lt;br /&gt;Be just as careful with with minor code as with major code, as you don't know in the end which will be more important.&lt;br /&gt;Consider what you lose when not writing the code properly against its gains, and consider the benefits of a poor implementation against what it loses.&lt;br /&gt;Focus on three things and you will avoid code repetition: Know what other code exists, others will review your code, the code will exist for a long time.&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;br /&gt;It's best to write code for the customer's demands, they will overlook its negative qualities.&lt;br /&gt;Code that's not written for those buying it will be for naught, and improving it will lead to code repetition.&lt;br /&gt;Those writing for a community should write the code for its own sake, those that came before you will help you.&lt;br /&gt;You will end up getting credit for the work that gets added on as if you yourself did it.&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;br /&gt;Be wary of standards bodies or other organizations, since they only recruit people for their own agenda.&lt;br /&gt;They will act like they love you when it is to their advantage, but they will not stand by you when you need it.&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;br /&gt;Desire what the community wants, and the community will want what you desire.&lt;br /&gt;Do what they want instead of what you want, and other programmers will desire what you desire.&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;br /&gt;Don't alienate the community.&lt;br /&gt;Don't trust code till the code is about to be recycled.&lt;br /&gt;Don't judge an implementation till you try to implement it yourself.&lt;br /&gt;Don't do something that is unaccepted hoping it will eventually be accepted.&lt;br /&gt;Don't plan to only write it properly later, maybe you won't.&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;br /&gt;An idiot doesn't care about code repetition.&lt;br /&gt;One who is unlearned will never be a hero.&lt;br /&gt;One who is embarrassed will never learn.&lt;br /&gt;One who is always angry and demanding can't teach.&lt;br /&gt;Those who solely focus on making money will never be more than an idiot.&lt;br /&gt;Wherever there is no one else to write the code, you write it.&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;br /&gt;The master who invented the above statement once looked at a hack being recycled, and stated:&lt;br /&gt;Since this hack replaced an older hack, it itself got replaced, and the hack replacing it will also be replaced.&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;br /&gt;One who increases code size increases bugs.&lt;br /&gt;One who increases features increases worry.&lt;br /&gt;One who increases threads increases overhead.&lt;br /&gt;One who increases processes increases communication layers.&lt;br /&gt;One who increases the amount of code they solely enjoy increases black magic in the code.&lt;br /&gt;One who increases usefulness of the code increases its lifespan.&lt;br /&gt;One who increases the amount of thought put into writing the code increases its intelligence.&lt;br /&gt;One who increases his own agenda only does so for himself.&lt;br /&gt;One who increases usefulness for the sake of the community will earn for himself everlasting gratitude.&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;br /&gt;If you write a lot of code, don't view yourself as so special, because it is for this reason you became a programmer.&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;br /&gt;The master who invented the above statement had five students.&lt;br /&gt;The first was someone who never overlooked a detail.&lt;br /&gt;The second always looked to the source of the issue.&lt;br /&gt;The third was a hero.&lt;br /&gt;The fourth always avoided code repetition.&lt;br /&gt;The fifth was always increasing his own understanding and knowledge of techniques.&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;br /&gt;The master said of his first student, if we weighed him against everyone else out there, his abilities would outweigh them all.&lt;br /&gt;Another master said, if the fifth student was weighed against the other four, his abilities would outweigh them all.&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;br /&gt;The master asked his students: What is the best trait for becoming a good programmer?&lt;br /&gt;The first answered: One who carefully checks his code.&lt;br /&gt;The second answered: One who has a good friend to bounce ideas off of.&lt;br /&gt;The third answered: One who sees the needs of those around him.&lt;br /&gt;The fourth answered: One who anticipates future needs.&lt;br /&gt;The fifth answered: One who desires to write the best code he can.&lt;br /&gt;The master stated, the fifth answered best, as his answer includes all the others.&lt;br /&gt;&lt;br /&gt;The master then asked his students: What should a good programmer avoid?&lt;br /&gt;The first answered: Ignoring what is going on in the code.&lt;br /&gt;The second answered: Idiot friends.&lt;br /&gt;The third answered: A weak community.&lt;br /&gt;The fourth answered: Allocating resources without freeing them.&lt;br /&gt;The fifth answered: Becoming complacent in his understanding of what is best.&lt;br /&gt;The master stated, the fifth answered best, as one who becomes complacent will end up with what everyone else answered.&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;br /&gt;Stick up for your fellow programmers as you would for yourself.&lt;br /&gt;Don't get angry easily.&lt;br /&gt;Fix the code before the problem is apparent.&lt;br /&gt;Enjoy the fire of clever code, but be careful lest you be burned by it.&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;br /&gt;Bad analyzing, no desire for good code, and hating your community will all cause one's code to be thrown away.&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;br /&gt;Managing resources you allocate should be as important to you as managing the resources you already have.&lt;br /&gt;Perfect your programming abilities, as this is what a programmer is.&lt;br /&gt;All your code should be written for its own sake.&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;br /&gt;Be meticulous in learning about what you need to accomplish, and the tools necessary to do so.&lt;br /&gt;Don't make the theory of prime importance.&lt;br /&gt;Don't underestimate yourself, and don't think your work will only be minor.&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;br /&gt;Have a good answer ready for those who may find issues with your code.&lt;br /&gt;Understand your customer.&lt;br /&gt;Understand your employer.&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;br /&gt;The day may be short, but there's a lot of work to be done.&lt;br /&gt;Programmers are lazy, even though their programs do much.&lt;br /&gt;The boss is demanding.&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;br /&gt;You don't have to do all the work by yourself, you don't have to finish every last bit of it.&lt;br /&gt;You however can't leave the code in disarray.&lt;br /&gt;If you write a lot of good code, you'll be properly compensated for it.&lt;br /&gt;Believe that those who employ you will compensate you for your effort.&lt;br /&gt;Know that those who put in the effort will be compensated greatly in years to come, even if not initially.&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;/ol&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/833174317742362874-239974731819219795?l=insanecoding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://insanecoding.blogspot.com/feeds/239974731819219795/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=833174317742362874&amp;postID=239974731819219795' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/833174317742362874/posts/default/239974731819219795'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/833174317742362874/posts/default/239974731819219795'/><link rel='alternate' type='text/html' href='http://insanecoding.blogspot.com/2009/05/ancient-coding-ideas-finally-in-english_25.html' title='Ancient coding ideas finally in English - Part 2'/><author><name>insane coder</name><uri>http://www.blogger.com/profile/06901386115570670209</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-833174317742362874.post-821862795615490728</id><published>2009-05-24T00:08:00.000-07:00</published><updated>2009-05-24T14:11:52.482-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Ancient Coding Ideas'/><title type='text'>Ancient coding ideas finally in English - Part 1</title><content type='html'>&lt;ol&gt;&lt;br /&gt;&lt;li&gt;&lt;br /&gt;Each great programmer learned programming from the master before him.&lt;br /&gt;Be precise in writing code.&lt;br /&gt;Teach programming to others, as you'll understand how things work better yourself when you're forced to explain it.&lt;br /&gt;Put safety in your code, don't just look at what minimally works, protect yourself from careless mistakes.&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;br /&gt;Good programs depend on 3 things:&lt;br /&gt;The code.&lt;br /&gt;The hardware.&lt;br /&gt;The presentation.&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;br /&gt;Don't write a program to get bare minimum done, and be over with it.&lt;br /&gt;Rather do it for the sake of the program itself, and try to get the most out of the program.&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;br /&gt;Your code should be welcome to other good programmers.&lt;br /&gt;You should pay attention to minor details of their code.&lt;br /&gt;Pay attention to their ideas.&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;br /&gt;Your code should be open for improvements.&lt;br /&gt;Let even simple programmers review it for mistakes.&lt;br /&gt;Be minimalistic on communication layers in your code.&lt;br /&gt;[The previous] refers to communicating with your own code, this applies even more so when your code has to communicate across a network or other external dependencies.&lt;br /&gt;Excessive external dependencies or communication across a network only hurts your program, and worsens code quality, and you'll end up with an unmanageable program.&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;br /&gt;Declare over yourself a coding standard.&lt;br /&gt;Buy yourself friends to bounce ideas off of.&lt;br /&gt;Accept every new idea for consideration, no matter how ridiculous it might seem at first glance.&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;br /&gt;Stay away from bad libraries.&lt;br /&gt;Don't statically link to them.&lt;br /&gt;Don't give up when it's a disaster out there.&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;br /&gt;Don't make yourself a sole reviewer of large amounts of code.&lt;br /&gt;When presented with two implementations, assume both of them are complete garbage until convinced otherwise.&lt;br /&gt;When having to decide between two implementations you are presented with, examine the pros and cons of the situation, and what improvements can be done, and be happy when proponents of each were able to walk away being able to accept the pros and cons and reach the best implementation.&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;br /&gt;Review code in depth, and have ever changing methods to do so, otherwise a severe bug can slip by you.&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;br /&gt;Love writing code.&lt;br /&gt;Hate bureaucracy.&lt;br /&gt;Don't give in to status quo.&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;br /&gt;Be careful in what you to say to others, or you may create a rift in your community, the outcome of the current work will fail, and your program will be for naught.&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;br /&gt;Love peace and run after it.&lt;br /&gt;Love the other programmers, and show them how to write better code.&lt;br /&gt;One who only seeks to advance his own self will end up destroying himself.&lt;br /&gt;One who doesn't learn what's new will end up not being able to write code with what he currently knows.&lt;br /&gt;One who doesn't learn at all shouldn't be writing code.&lt;br /&gt;One who doesn't use libraries the way they're supposed to be used will be lost in the end.&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;br /&gt;If you don't write the code, who is going to write it for you?&lt;br /&gt;If you're always writing all the libraries yourself, what's the point?&lt;br /&gt;If you don't write it today, then when exactly?&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;br /&gt;Take programming seriously.&lt;br /&gt;Optimize the little bits which do the most.&lt;br /&gt;Welcome all patches with a smile (even if you don't commit them all).&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;br /&gt;Make for yourself a system, and stay away from assumptions, learn about it if you're not sure.&lt;br /&gt;Don't write a program based on rough estimates.&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;br /&gt;I've spent a lot of time with those who know only theory. Don't argue with them, just pay attention.&lt;br /&gt;The theory isn't the main thing, but the practical. If you dwell on the theory, you'll end up being repetitious with your code.&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;br /&gt;On three things a good program depends on:&lt;br /&gt;Meeting Requirements.&lt;br /&gt;Correctness.&lt;br /&gt;Peace with the community.&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/833174317742362874-821862795615490728?l=insanecoding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://insanecoding.blogspot.com/feeds/821862795615490728/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=833174317742362874&amp;postID=821862795615490728' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/833174317742362874/posts/default/821862795615490728'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/833174317742362874/posts/default/821862795615490728'/><link rel='alternate' type='text/html' href='http://insanecoding.blogspot.com/2009/05/ancient-coding-ideas-finally-in-english.html' title='Ancient coding ideas finally in English - Part 1'/><author><name>insane coder</name><uri>http://www.blogger.com/profile/06901386115570670209</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-833174317742362874.post-6223630293830268144</id><published>2009-05-12T19:45:00.000-07:00</published><updated>2009-05-25T17:53:15.260-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='GTK'/><category scheme='http://www.blogger.com/atom/ns#' term='GNOME'/><category scheme='http://www.blogger.com/atom/ns#' term='Library'/><category scheme='http://www.blogger.com/atom/ns#' term='Windows'/><category scheme='http://www.blogger.com/atom/ns#' term='PC'/><category scheme='http://www.blogger.com/atom/ns#' term='school'/><category scheme='http://www.blogger.com/atom/ns#' term='closed source'/><category scheme='http://www.blogger.com/atom/ns#' term='Firefox'/><category scheme='http://www.blogger.com/atom/ns#' term='KDE'/><category scheme='http://www.blogger.com/atom/ns#' term='open source'/><category scheme='http://www.blogger.com/atom/ns#' term='ALSA'/><category scheme='http://www.blogger.com/atom/ns#' term='gnu'/><category scheme='http://www.blogger.com/atom/ns#' term='API'/><category scheme='http://www.blogger.com/atom/ns#' term='OSS'/><category scheme='http://www.blogger.com/atom/ns#' term='Qt'/><category scheme='http://www.blogger.com/atom/ns#' term='GUI'/><category scheme='http://www.blogger.com/atom/ns#' term='Portability'/><title type='text'>Will Linux ever be mainstream?</title><content type='html'>Constantly different sites and communities always discuss the possibility of Linux becoming mainstream and when the mainstreaming will take place. Often reasons are laid out where Linux is lacking. Most reasons don't seem to be in touch with reality. This will be an attempt to go over some of those reasons, cut out the fluff from the fact, and perhaps touch on a few areas that have not been gone over yet.&lt;br /&gt;&lt;br /&gt;One could argue with today's routers that Linux is already mainstream, but let us focus more on full blown computer Linux, which runs on servers, workstation, and home computers.&lt;br /&gt;&lt;br /&gt;When it comes to servers, the question really is who isn't running Linux? Practically every medium sized or larger company runs Linux on a couple of their servers. What makes Linux so compelling that many companies have at least one if not many Linux servers?&lt;br /&gt;&lt;br /&gt;Servers are a very different breed of computer than the workstation or home computer. "Desktop Linux" as it's known is the type of OS for average everyday Joe. Joe is the kind of guy who wants to sit down and do a few specific tasks. He expects those tasks to be easy to do, and be mostly the same on every computer. He doesn't expect anything about the 'tasks' to scare him. He accepts the program may crash or go haywire in the middle, at which time it's just new cup of coffee time. Except Desktop Linux isn't for every day Joe ... yet.&lt;br /&gt;&lt;br /&gt;Servers on the other hand are designed primarily for functionality. They have to have maximum up time. It doesn't matter if the server is hard to understand, and work with, and only two guys in the whole office can make heads or tails out of it. It's okay that the company needs to hire two guys with PhDs, who are complete recluses, and never attend a single office party.&lt;br /&gt;&lt;br /&gt;Windows servers are primarily used by those that need special Windows functionality at the office, such as ActiveDirectory, or Exchange so everyone has integrated Outlook. Some even use Windows as HTTP Servers and the like. Windows is less known for working, but being great for those specialized tasks, or servers which don't need those two PhD recluses to manage. Even guys who have never written a piece of code in their entire life can manage a Windows server - usually. Microsoft always tries to press this latter point home with all their get the facts campaigns.&lt;br /&gt;&lt;br /&gt;The real fact is though that companies on their servers need functionality, reliability, and countability. While larger companies would prefer to replace every man with a machine which is guaranteed to last forever and not require a single ounce of maintenance, they would rather rely on personnel than hardware. Sure, when I'm a really small business, I'd rather have a server I can manage myself and have a clue what I'm doing, but if I had the money, I'd rather have expert geeky Greg who I can count on to keep our hardware setup afloat. Even when geeky Greg is a bit more expensive than laid-back Larry, I'm happier knowing that I have the best people on the job.&lt;br /&gt;&lt;br /&gt;Windows servers while being great in their niches, are also a pain in the neck in more generalized applications. We have a Windows HTTP/FTP server at work. One day it downloads security patches from Microsoft, and suddenly HTTP/FTP stop working entirely. Our expert laid-back Larry spent a few hours looking at the machine trying to find out what changed, and mostly had to resort to using Google as opposed to any knowledge of how Windows works. Finally he sees on some site that Microsoft changed some firewall settings to be extra restrictive, and managed to fix the problem.&lt;br /&gt;&lt;br /&gt;Another time, part of the server got hacked into, and we have to reinstall most of it. For some reason, a subsection of our site just refused to work, apparently a permission problem somewhere. On Linux/Apache, permission problems are either a setting in Apache or on the file system, easy to find. Windows on the other hand, with their oh-so-much-better fine grained permission support seem to have dozens if not hundreds of places where to look for security settings. This took our Larry close to two weeks to fix.&lt;br /&gt;&lt;br /&gt;Yet another time, a server application which we wrote in-house ran flawlessly on both Linux and Windows XP. However, when we installed it on our Windows Server 2003 server, it inexplicably didn't work. It's no wonder companies use Linux servers for many server tasks. There's also a decent amount of server applications a company can purchase from Red Hat, IBM, Oracle, and a couple of other companies. Linux on the server clearly rocks, even various statistical sites &lt;a href="http://www.securityspace.com/s_survey/data/200904/index.html"&gt;agree&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Now let us move on to the workstation and home computer segment, where we'll see a very different picture.&lt;br /&gt;&lt;br /&gt;On the workstation, two features are key, manageability, and usability. Companies like to make sure that they can install new programs across the board, that they can easily update across the board, and change settings on every single machine in the office from one location. Granted on Linux one can log in as root to any machine and do what they want, but how many applications are there that allow me to automate management remotely? For example, apt-get (and its derivatives) are known as one of the best package managers for Desktop Linux, yet they don't have any way to send a call to update to every single machine on a network. Sure using NFS I can have an ActiveDirectory like setup where any user can log into any machine and get their settings and files, but how exactly do I push changes to the software on the machines themselves? Every place I asked this question to seems to have their own customized setup.&lt;br /&gt;&lt;br /&gt;One place SSHs into every single machine individually, and then paste some huge command into the terminal. Another upgrades one machine, mirrors the hard drive, then goes to each machine in turn and re-images the installed hard disk. One place which employs a decent number of programmers wrote a series of scripts which every night download a file from a server and execute it. Another, also with an excellent programming task force, wrote their own SSH based application which logs into every machine on the network and runs whichever commands the admin puts in on all of them, allowing real time pushing of updates to all the machines at once.&lt;br /&gt;&lt;br /&gt;Is it any wonder that a large company is scared to have Linux on all their machines or that it really is expensive to maintain? We keep toting/hearing how amazing X is because of the client/server setup, or these days in regards to PulseAudio, let us start hearing it for massive remote management. And remember not to limit this just to installing packages, we need to be able to change system files remotely and simultaneously, with a method which becomes standard.&lt;br /&gt;&lt;br /&gt;The other aspect if of course usability, and by usability I mean being able to use the kind of software the company needs. Now for some companies, documents, spreadsheets, and web browsers are the extent of the applications they need, and for that we're already there. Unless of course they also need 100% compatibility with the office suites used by other companies.&lt;br /&gt;&lt;br /&gt;What about specialized niches though? That's where real companies have their major work done. These companies are using software to manage medical history, other clientèle meta-data, stocks (both monetary and in-store), and multitudes of other specialized fields. All these applications more or less connect to some server somewhere and do database manipulation. We're really talking about webapps in desktop form. Why is every last one of these 3rd party applications only written for Windows?&lt;br /&gt;&lt;br /&gt;The reasons are probably threefold. If these applications worked in any standard browser, we're really providing more functionality in them than should be exposed to the user. Do you want the user to hit stop or the close button in the corner of their browser in middle of a transaction? Sure, the database should be robust and atomic enough to handle these kinds of situations, but do we want to spoon-feed these situations to the users? We also certainly don't want general system upgrades which would install a newer version of the browser to break one of the key applications being used by the company. To solve this problem requires a custom browser, bringing us back to square one when it comes to making this a desktop application.&lt;br /&gt;&lt;br /&gt;The next reason is known as catch-22. Why should a generic company making an application bother with anything than the most popular OS by a landslide? We need way more Desktop Linux users for a company to bother, but if the companies don't bother, it's unlikely that Desktop users will switch to Linux. Also, &lt;a href="http://insanecoding.blogspot.com/2007/03/applications-and-difficulties-of.html"&gt;as I've said before&lt;/a&gt;, portability isn't difficult in most cases, but most won't bother unless we enlighten them.&lt;br /&gt;&lt;br /&gt;Lastly, many of these applications are old, or at least most of their code base is. There's just no incentive to rewrite them. And when one of these applications is made in-house, it'll be made for what the rest of the company is already running.&lt;br /&gt;&lt;br /&gt;To get Linux onto the workstation then, we need the following to take place:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Creation of standardized massive management tools&lt;/li&gt;&lt;li&gt;Near perfect interoperability of office suites&lt;/li&gt;&lt;li&gt;Get ports of Linux office suites to be mainstream on Windows too&lt;/li&gt;&lt;li&gt;Get work oriented applications on Windows to be written portably&lt;/li&gt;&lt;li&gt;Make Linux more popular on the Desktop in all aspects&lt;/li&gt;&lt;/ul&gt;We have to stop being scared of Open Source on closed sourced Operating Systems, if half the offices out there used Open Office on Windows, they wouldn't mind running Open Office on Linux, and they won't have any different interoperability issues that they don't already have.&lt;br /&gt;&lt;br /&gt;We also need to make portability excellence more the norm. These companies could benefit a lot from using Qt for example. Qt has great SQL support. Qt contains a web browser so webapps can be made without providing anything unnecessary in the interface. Qt also has great easy to use client/server support, with SSL to boot. Also, Qt applications are probably the easiest type to make multilingual, and the language can be changed on the fly, which is very important for apps used world wide, or for companies looking to save money by hiring immigrants. Lastly, Qt is easier to use than the Win32 API for these relatively basic applications. If they used 100% Qt, the majority of the time, the program would work on Linux with just a simple recompile.&lt;br /&gt;&lt;br /&gt;For the above to happen we really need a major Qt push in the developer community. The fight between GTK, wxWidgets, and Qt is going to be hurting us here. Sure, initially Qt was a lot more closed, and we needed GTK to push Qt in the right direction. But today, Qt is LGPL, offers support/maintenance contracts, and is a good 5-10 years ahead of GTK in breadth of features supplied. Even if you like GTK better for whatever reason, it really can't stand up objectively to Qt from the big business perspective. We need developers to get behind our best development libraries. We also need to get schools to teach the libraries we use as part of the mainstream curriculum. Fracturing the community on this point is only going to hurt us in the long run.&lt;br /&gt;&lt;br /&gt;Lastly, we come to Linux on the home computer. What do we need on a home computer exactly? They're used for personal finances, homework, surfing the web, multimedia, creativity, and most importantly, gaming.&lt;br /&gt;&lt;br /&gt;Are the finance applications available for Linux good enough? I really have no idea, perhaps someone can enlighten me in the comments. We'll get back to this point shortly.&lt;br /&gt;&lt;br /&gt;For homework, I'd say Linux was there already. We have Google and Wikipedia available via the world wide web. Dictionaries and Thesauruses are available too. We got calculators and documents, nothing is really missing.&lt;br /&gt;&lt;br /&gt;For surfing the web we're definitely there, no questions asked.&lt;br /&gt;&lt;br /&gt;Multimedia we're also there aside from a few annoyances. I'll discuss this more below.&lt;br /&gt;&lt;br /&gt;For creativity, I'm not sure where we are. Several years back, it seems all the kids used to love making greeting cards, posters, and the like using programs such as The Print Shop Deluxe or Print Artist. Do we have any decent equivalents on Linux?&lt;br /&gt;&lt;br /&gt;Thing is, a company would have to be completely insane to port popular home publishing software to Linux. First there's all the reasons mentioned above regarding catch-22 and the like. Then there's nutjobs like Richard Stallman out there who will crucify the company attempting to port their software to Linux. For starters, see &lt;a href="http://www.fsf.org/campaigns/priority.html"&gt;this article&lt;/a&gt; which says:&lt;br /&gt;&lt;blockquote&gt;Some of the most important projects on our list are &lt;strong&gt;replacement projects&lt;/strong&gt;. These projects are important because they address areas where users are continually being seduced into using non-free software by the lack of an &lt;span style="font-style: italic;"&gt;adequate&lt;/span&gt; free replacement.&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;Notice how they're trying to crush Skype for example. Basically any time a company will port their application to Linux, and it becomes popular enough on Desktop Linux, you'll have these nutjobs calling for the destruction of said program by completely reimplementing it and giving it away for free. And reimplement it they do, even if not as effectively, but &lt;span style="font-weight: bold;"&gt;adequate&lt;/span&gt; enough to dissuade anyone from ever buying the application. Then the free application gets ported to Windows too, effectively destroying the company's business model and generally the company itself. Don't believe they'll take it that far? Look how far they went to stop Qt/KDE. Remember all those old office suites and related applications available for Linux a decade ago? How many of them are still around or in business? When free versions of voice chatting are available on all platforms, and can even interface with standard telephones, do you think Skype will still be around?&lt;br /&gt;&lt;br /&gt;Basically, trying to port a popular application to Linux is a great way to get yourself a death sentence. If for example Adobe ever ported Photoshop to Linux, there'd be such a massive upsurge in getting the GIMP or a clone to have a sane interface, and get in some of those last features, Photoshop would probably be dead in a year.&lt;br /&gt;&lt;br /&gt;And unless some of these applications are ported to Linux, we'll probably never see niche applications as good as their Windows counterparts. Many programmers just don't care enough to develop these to the extent needed, and some only do so when they feel it's part of a holy war. Thus giving us a whole new dimension to the catch-22.&lt;br /&gt;&lt;br /&gt;Finally, we come to gaming. Is Linux good enough for companies to develop for? First glance, and you think a resounding yes. A deeper look reveals otherwise. First off, there's good ol` video. For the big games today, it's all about graphics. How many video cards provide full modern OpenGL support on Linux? The problem is basically as follows. X Windows a system designed way back when with all sorts of cool ideas in mind, where the current driver API is simply not enough to take full advantage of accelerated OpenGL. You can easily search online and find tons of results on why X is really bad, but it really stands out when it comes to video.&lt;br /&gt;&lt;br /&gt;NVidia has for several years now put out "evil drivers" which get the job done, and provide fantastic OpenGL support on top of Linux. The drivers though are viewed as evil, since they bypass the bottom 1/3 of X and talk straight to the Kernel, and don't fully follow the X driver API. And of course, they're also closed source. All the other drivers today for the most part communicate with the system via the X API, especially the open sourced drivers. Yet they'll never measure up, because X prevents them from measuring up. But they'll continue to stick to what little X does provide. NVidia keeps citing they can't open source their drivers because they'll lose their competitive advantage. Many have questioned this, as for the most part, the basic principals are the same on all cards, what is so secret in their drivers? When in reality, if they open sourced their drivers, the core functionality would probably be merged into X as a new driver API, allowing ATI and Intel to compete on equal footing, losing their competitive advantage. It's not the card per sè they're trying to hide, but the actual driver API that would allow all cards to take advantage of themselves, bypassing any stupidity in X. At the very least, ATI or Intel could grab a lot of that code and make it easier for themselves to make an X-free driver that works for X well.&lt;br /&gt;&lt;br /&gt;When it comes down to it, as tiny as the market share is that Linux already has, it becomes even smaller if you want to release an application that needs good video support. On the other hand, those same video cards work just fine in Windows.&lt;br /&gt;&lt;br /&gt;Next comes sound, which I have discussed &lt;a href="http://insanecoding.blogspot.com/2007/05/sorry-state-of-sound-in-linux.html"&gt;before&lt;/a&gt;. The main sound issue for games is latency, and ALSA (the default in Linux) is really bad in that regard. This gets compounded when sound has to run through a sound server on its way to the drivers that talk to the sound card. For playing music, ALSA seems just fine to everybody, you don't notice or care that the sound starts or stops a moment or two after you press the button. For videos as well, it's generally a non-issue. In most video formats, the video takes longer to decode than it does to process sound, so they're ready at the same time. It also doesn't have to be synced for input. So everything seems fine. In the worst case scenario, you just tell your video player to alter the video/audio sync slightly, and everything is great.&lt;br /&gt;&lt;br /&gt;When it comes to games, it's an entirely different ballpark. For the game not to appear laggy, the video has to be synced to the input. You want the gun to fire immediately after the user presses the button, without a lag. Once the bullet hits the enemy and the user sees the enemy explode, you want them to hear that enemy explode. The audio has to be synched to the video. Players will not accept having the sound a second or two late. Now means now. There's no room for all the extra overhead that is currently required.&lt;br /&gt;&lt;br /&gt;I find it mind boggling that Ubuntu, a distribution designed for average Joe, decided to make the entire system routed through PulseAudio, and see it as a good thing. The main advantage of PulseAudio is that it has a client/server architecture so that sound generated on one machine can be output on another. How many home users know of this feature, let alone have a reason to use it? The whole system makes sound lag like crazy.&lt;br /&gt;&lt;br /&gt;I once wrote a game with a few other developers which uses SDL or libao to output sound. Users way back when used to enjoy it. Nowadays with ALSA, and especially with PulseAudio which SDL and libao default to outputting to in Ubuntu, users keep complaining that the sound lags two or more seconds behind the video. It's amazing this somehow became the default system setup.&lt;br /&gt;&lt;br /&gt;Next is input. This one is easy right? Linux surely supports input. Now let me ask you this, how many KDE or GNOME games have you seen that allow you to control them via a Joystick/Gamepad? The answer is quite simply, none of them do. Neither Qt nor GTK provide any input support other than keyboard or mouse. That's right, our premier application framework libraries don't even support one of the most popular inventions of the 80s and 90s for PC gamers.&lt;br /&gt;&lt;br /&gt;Basically, here you'll be making a game and using your library to handle both keyboard and mouse support, when you want to add on joystick support, you'll have to switch to a different library, and possibly somehow merge a completely different event loop into the main one your program uses for everything else. Isn't it so much easier on Windows where they provide a unified input API which is part of the rest of the API you're already using?&lt;br /&gt;&lt;br /&gt;Modern games tend to include a lot of sound, and more often than not, video as well. It'd be nice to be able to use standard formats for these, right? The various APIs out there, especially Phonon (part of Qt/KDE) is great at playing sound or video for you. But which formats should you be putting your media in? Which formats are you ensured will be available on the system you're deploying on? Basically all these libraries have multiple backends where support can be drastically different, and the most popular formats, such as those based on MPEG standards don't come standard on most Linux distributions, thanks to them being "non free". Next you'll think fine, let us just ship the game with uncompressed media. This actually works fine for audio, but is a mess when it comes to video. Try making a pure uncompressed AVI and running it in Xine, MPlayer, and anything else that can be used as a Phonon back end. No two video players can agree on what the uncompressed AVI format is. Some display the picture upside down, some have different visions of which byte signifies red, blue, and green, and so on.&lt;br /&gt;&lt;br /&gt;For all of these reasons, the game market, currently the largest in home software, has difficultly designing and properly deploying games on Linux. The only companies which have managed to do it in the past are those that made major games for DOS back in the day, where there also was no good APIs or solutions for doing anything.&lt;br /&gt;&lt;br /&gt;Now that we wrapped it all up from the actual applications side of things, let us have a look at actual usability for the home user.&lt;br /&gt;&lt;br /&gt;We're taken back to average Joe who wants to setup his machine. He's not sure what to do. But he hears there are great Ubuntu forums where he can ask for help. He goes and asks, and gets a response similar to the following:&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;Open a terminal, then type:&lt;br /&gt;sudo /etc/init.d/d restart&lt;br /&gt;ln -s /alt/override /bin/appstart&lt;br /&gt;cd /etc/app&lt;br /&gt;sudo nano b.conf&lt;br /&gt;&lt;enter password=""&gt;&lt;br /&gt;Preload=yes&lt;br /&gt;ctrl+x&lt;br /&gt;yes&lt;br /&gt;&lt;/enter&gt;&lt;/blockquote&gt;&lt;br /&gt;Does anyone realize how intimidating this is? Even if average Joe was really Windows Power User Joe, does he really feel safe entering commands with which he is unfamiliar?&lt;br /&gt;&lt;br /&gt;In the Windows world, we'd tell such a user to open up Windows Explorer, navigate to certain directories, copy files, edit files with notepad and the like. Is it really so hard to tell a user to open up Nautilus or Dolphin or whatever their file manager is, and navigate to a certain location and edit a file with gedit/kwrite?&lt;br /&gt;&lt;br /&gt;Sure, it is faster to paste a few quick commands into the terminal, but we're turning away potential users. The home user should &lt;span style="font-weight: bold;"&gt;never&lt;/span&gt; be told he has to open a terminal. In 98% of the cases he really doesn't and what he wants/needs can be done via the GUI. Let us start helping these users appropriately.&lt;br /&gt;&lt;br /&gt;Next is the myth about compiling. I saw an article written recently that Linux sucks because users have to compile their own software. I haven't compiled any software on Linux in years, except for those applications that I work on myself. Who in the world is still perpetuating this myth?&lt;br /&gt;&lt;br /&gt;It's actually sad to see some distributions out there that force users to recompile stuff. No I'm not talking about Gentoo, but Red Hat actually. We have a server running Red Hat at work, we needed mod_rewrite added to it the other day. Guess what? We had to recompile the server to add that module. On Debian based distros one just runs "a2enmod rewrite", and presto the module is installed. Why the heck are distros forcing these archaic design principals on us?&lt;br /&gt;&lt;br /&gt;Then there's just the overall confusion, which many others point out. Do I use KDE or GNOME? Pidgin or Kopete? Firefox or Konqueror? X-Chat or Konversation? VLC or MPlayer? RPM or DEB? The question is, is this a problem? So what if we have a lot of choices.&lt;br /&gt;&lt;br /&gt;The issue arises when the choice breaks down the field. When deploying applications this can get especially nightmarish. We need to really focus more on providing just the best solution, and improving the best solution if it's lacking in an area, as opposed to having multiple versions of everything. OSS vs. ALSA, RPM vs. DEB, and a bunch of others which are base to the system shouldn't really be around these days.&lt;br /&gt;&lt;br /&gt;The other end of the spectrum is less important to providing a coherent system for deploying on. But it does confuse some users. When I want to help someone, do I just assume they use Krusader as a file manager? Should I try to be generic about file managers? Should I have them install Krusader so I can help them? This theme is played over in many variations on most Linux help forums.&lt;br /&gt;"Oh yes, go open that in gedit."&lt;br /&gt;"Gedit? What's Gedit?"&lt;br /&gt;"Are you running KDE or GNOME?"&lt;br /&gt;"GNOME"&lt;br /&gt;"Are you sure?"&lt;br /&gt;"Wait, are GNOME and XFCE the same thing?"&lt;br /&gt;&lt;br /&gt;What's really bad though is when users understand there's multiple applications, but can't find one to satisfy them. It's easy when the choices are simple or advanced, you choose the one more suited to your tastes for that kind of application. But it gets really annoying when one of those apps tries to be like the other. Do we need two apps that behave exactly the same but are different? If you started different, and you each have your own communities, then stay different. We don't need variety when there is no real difference. KDE 4 trying to be more like GNOME is just retarded. Trying to steal GNOME's user base by making a design which appeals more to GNOME users but has a couple of flashy features isn't a way to grow your user base, it's just a way to swap one for another.&lt;br /&gt;&lt;br /&gt;Nintendo in the past couple of years was faced with losing much of their user base to Sony. For example, back in the late 90s, all the cool RPGs for which Nintendo was known, had all sequels moved to Sony hardware. However, instead of trying to win back old gamers, they took an entirely different approach. Nintendo realized the largest market of gamers weren't those on the other systems, but those that weren't on any systems. The largest market available for targeting is generally those users not yet in the market, unless the market in question is already ubiquitous.&lt;br /&gt;&lt;br /&gt;That said, redesigning an existing program to target those who are currently non-users can sometimes have the potential to alienate loyal users, depending on what sort of changes are necessary, so unless pulling in all the non-users is guaranteed, one should be careful with this strategy. Although a user base with non paying customers is more likely to have success with such a drastic change, as they aren't dependent on their users either way. Balance is required, so many new users are acquired while a minimal amount of existing users are alienated.&lt;br /&gt;&lt;br /&gt;To get Linux on home computers the following needs to take place:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-size:100%;"&gt;We need to stop fighting every company that ports a decent product to Linux&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size:100%;"&gt;We should write good programs even if there is nothing else to compete with on Linux&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size:100%;"&gt;We shouldn't leave programs as adequate&lt;br /&gt;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size:100%;"&gt;We need a real solution to the X fiasco&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size:100%;"&gt;We need a real solution to the sound mixing/latency fiasco, and clunky APIs and more sound servers isn't it&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size:100%;"&gt;We need to offer tools to the gaming market and try to capture it&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size:100%;"&gt;Support has to be geared towards the users, not the developers&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size:100%;"&gt;Stop the myths, and prevent new users installing distros that perpetuate them&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size:100%;"&gt;Stop competition between almost identical programs&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size:100%;"&gt;Let programs that are similar but very different go their own ways&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size:100%;"&gt;Bring in users that don't use anything else&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size:100%;"&gt;Keep as many old users as possible and not alienate them&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;Linux being so versatile is great, and hopefully it will break into new markets. As I said before, many routers use Linux. To be popular on the desktop though, it either has to get users to desktops that currently don't have any, or manage to steal users from other desktops while keeping the ones they have. Becoming Windows isn't the answer, as others like to point out, but competing toe to toe in all existing areas while obtaining new ones is. In some areas, we may just have to throw away existing users to an extent (possibly eliminate X), if we want to grab everyone else out there.&lt;br /&gt;&lt;br /&gt;Speaking of versatility, has everyone seen &lt;a href="http://labs.trolltech.com/blogs/2008/12/02/widgets-enter-the-third-dimension-wolfenqt/"&gt;this&lt;/a&gt;? Linux grown technology does in many ways have the potential to beat Windows and the rest in a large way.&lt;br /&gt;&lt;br /&gt;Everyone remember Duke Nukem Forever? Supposedly the best game ever, since it has unprecedented levels of world operability within the game? Such as being able to go to a soda machine, put in some money, press buttons, and buy a drink. With Qt, we can provide a game with panels throughout it where a user can control many things within the game, and there'd be a rich set of controls developers can easily add. Imagine playing a game where you go checkout the enemy's computer system, the system seeming pretty normal, you can bring up videos of plans they plan on. Or notice a desktop with a web browser, where you yourself can go ahead and login and check your E-Mail within the game itself, providing a more real experience. Or the real clincher. You know those games where plot-wise you break into the enemy factory and reprogram the robots or missiles or whatever? With Qt, the "code" you're reprogramming can be actual JavaScript code used in game. If made simple enough, it can seem realistic, and really give a lot of flexibility to those that want to reprogram the enemy's design. We have the potential to provide unprecedented levels of gameplay in games. If only we could get companies to put out games using Qt+OpenGL+Phonon, which they will probably not even consider looking at until Qt has Joystick support. Even then we still need to promote Qt more, which will make it easier to get companies to port games to Linux...&lt;br /&gt;&lt;br /&gt;I think Ubuntu has some good ideas for adopting home users, but could be improved upon in many ways. Ultimately, we need a lot of change in the area of marketing to home users. There's so much that needs to be fixed and in some areas, we're not even close.&lt;br /&gt;&lt;br /&gt;Feel free to post your comments, arguments, and disagreements.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/833174317742362874-6223630293830268144?l=insanecoding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://insanecoding.blogspot.com/feeds/6223630293830268144/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=833174317742362874&amp;postID=6223630293830268144' title='18 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/833174317742362874/posts/default/6223630293830268144'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/833174317742362874/posts/default/6223630293830268144'/><link rel='alternate' type='text/html' href='http://insanecoding.blogspot.com/2009/05/will-linux-ever-be-mainstream.html' title='Will Linux ever be mainstream?'/><author><name>insane coder</name><uri>http://www.blogger.com/profile/06901386115570670209</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>18</thr:total></entry><entry><id>tag:blogger.com,1999:blog-833174317742362874.post-583254528084394891</id><published>2009-05-12T12:45:00.001-07:00</published><updated>2009-05-12T13:07:29.588-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='KDE'/><category scheme='http://www.blogger.com/atom/ns#' term='Mozilla'/><category scheme='http://www.blogger.com/atom/ns#' term='BIOS'/><category scheme='http://www.blogger.com/atom/ns#' term='x86'/><category scheme='http://www.blogger.com/atom/ns#' term='Windows'/><category scheme='http://www.blogger.com/atom/ns#' term='PC'/><category scheme='http://www.blogger.com/atom/ns#' term='Mac OS X'/><title type='text'>What the heck is a PC?</title><content type='html'>So the other day a friend of mine comes over to discuss some business strategy. After chatting for a bit, he asks me if he could use one of my computers to check his E-Mail. Happily obliging, I log into one of my x86-64 machines running Linux/KDE, open up Firefox for him, and tell him to go check.&lt;br /&gt;&lt;br /&gt;So my friend sits down, grabs for the mouse and keyboard, and starts looking at the screen with a weird expression on his face. After a couple of seconds, he clicks on the address bar, looks around a bit more, then he motions to me that he could use some help.&lt;br /&gt;&lt;br /&gt;I asked him if he used a particular web based e-mail service, he answered in the affirmative that he uses G-Mail. So I typed in the address to G-Mail for him, which brought up the login page asking for his username and password.&lt;br /&gt;&lt;br /&gt;He again looks at the screen, types in his username, then pauses again. He turns to me and tells me he feels really uncomfortable using this system, do I have a PC available that he can use?&lt;br /&gt;&lt;br /&gt;This question made me completely flabbergasted. My friend is technically oriented, he's been using computers for a decade, he knows various operating systems exist, he knows various web browsers exist. He uses Firefox both at home and work. He even does some VBA scripting in his Excel spreadsheets. What in the world is scaring him about Firefox in Linux/KDE?&lt;br /&gt;&lt;br /&gt;As the story continues, I turn to my friend and tell him this is a PC. He looks back at the screen, looks a bit startled, then seems to think for a few moments. Finally he turns to me and says, you know, Windows? So I reboot the machine into Windows XP (all my computers are minimally dual boot), and open up Firefox for him. He sits down happily and checks his E-Mail.&lt;br /&gt;&lt;br /&gt;This experience left me thinking though. What the heck is a PC? It seems some people today have got it in their skulls that PC is a connotation for Windows. PC-DOS, PC-BSD, and other OSs must appear oxymoronish to these people if they ever saw them.&lt;br /&gt;&lt;br /&gt;Thinking about it, I always for years viewed a PC as something IBM put together, most importantly containing an x86 processor. The basic machine changed over the years, but it was always x86. But then Apple released computers on x86 chips too recently, and they vehemently deny that they use PC hardware. Their basic difference being they don't use any classic PC BIOS.&lt;br /&gt;&lt;br /&gt;Should we now take the term PC to mean x86+BIOS? Thinking more about it, a PC should probably be defined as a computer capable of running MS/PC DOS. Maybe even Apple decided to use their whole EFI setup just so they can classify their computers as not PCs. And thanks to dumb marketing, people are now thinking PC means running Windows.&lt;br /&gt;&lt;br /&gt;So, do you know anyone who is scared of the same browser on a different OS? What do you think of when you hear "PC"? Has the PC definition changed? Should it change?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/833174317742362874-583254528084394891?l=insanecoding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://insanecoding.blogspot.com/feeds/583254528084394891/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=833174317742362874&amp;postID=583254528084394891' title='13 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/833174317742362874/posts/default/583254528084394891'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/833174317742362874/posts/default/583254528084394891'/><link rel='alternate' type='text/html' href='http://insanecoding.blogspot.com/2009/05/what-heck-is-pc.html' title='What the heck is a PC?'/><author><name>insane coder</name><uri>http://www.blogger.com/profile/06901386115570670209</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>13</thr:total></entry><entry><id>tag:blogger.com,1999:blog-833174317742362874.post-2540523401286659863</id><published>2008-12-17T20:33:00.000-08:00</published><updated>2008-12-17T21:12:14.421-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='open source'/><category scheme='http://www.blogger.com/atom/ns#' term='gnu'/><category scheme='http://www.blogger.com/atom/ns#' term='GCC'/><category scheme='http://www.blogger.com/atom/ns#' term='Windows'/><category scheme='http://www.blogger.com/atom/ns#' term='closed source'/><title type='text'>GPLv3 - Is it right for your family?</title><content type='html'>The &lt;a href="http://www.gnu.org/licenses/gpl-3.0.txt"&gt;GPLv3&lt;/a&gt; came out a while ago, with a changed outlook from v2, which upset many people, with some choosing to relabel their software from being GPLv2 or higher to GPLv2 only.&lt;br /&gt;&lt;br /&gt;While discussing some changes with someone the other day, I looked over this section again:&lt;br /&gt;&lt;blockquote&gt;A compilation of a covered work with other separate and independent&lt;br /&gt;works, which are not by their nature extensions of the covered work,&lt;br /&gt;and which are not combined with it such as to form a larger program,&lt;br /&gt;in or on a volume of a storage or distribution medium, is called an&lt;br /&gt;"aggregate" if the compilation and its resulting copyright are not&lt;br /&gt;used to limit the access or legal rights of the compilation's users&lt;br /&gt;beyond what the individual works permit.  Inclusion of a covered work&lt;br /&gt;in an aggregate does not cause this License to apply to the other&lt;br /&gt;parts of the aggregate.&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;From what I gather, the intent of this paragraph was to define how the GPL affects hardware manufactures that embed GPL software on their products. They wanted to allow companies to ship various software together, as long as the user of the product doesn't have any legal restrictions applied to them. For example: &lt;span style="font-style:italic;"&gt;By opening this package you forgo your rights to ever resell the contents within.&lt;/span&gt; Or: &lt;span style="font-style:italic;"&gt;You agree to not use this product in order to reverse engineer it.&lt;/span&gt; Or the real clincher: &lt;span style="font-style:italic;"&gt;By opening the packaging or using this product you agree to not attempt to modify it.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Basically this is done to explicitly state the GPLs new intent:&lt;br /&gt;&lt;blockquote&gt;Some devices are designed to deny users access to install or run&lt;br /&gt;modified versions of the software inside them, although the manufacturer&lt;br /&gt;can do so.  This is fundamentally incompatible with the aim of&lt;br /&gt;protecting users' freedom to change the software.  The systematic&lt;br /&gt;pattern of such abuse occurs in the area of products for individuals to&lt;br /&gt;use, which is precisely where it is most unacceptable.  Therefore, we&lt;br /&gt;have designed this version of the GPL to prohibit the practice for those&lt;br /&gt;products.  If such problems arise substantially in other domains, we&lt;br /&gt;stand ready to extend this provision to those domains in future versions&lt;br /&gt;of the GPL, as needed to protect the freedom of users.&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Now under the GPLv3, one is unable to sell hardware with GPLv3 on it to someone which somehow limits their legal rights they had prior to owning hardware.&lt;br /&gt;&lt;br /&gt;Now what exactly defines legal rights? One's legal rights change from location to location. One has legal rights and restrictions based on the country they live in. They also have legal restrictions added on to those by the state they live in. One who owns a domain may also limit the rights of those who wish to stay within their domain. When one lives in a domain, and violates a law of that particular domain, they may be punished by the rules of that domain, as long as the punishment isn't in conflict with the rights and restrictions provided by the domain that particular domain is contained within.&lt;br /&gt;&lt;br /&gt;Meaning, I can establish rights and regulations within my own household that are binding to members within it, as long as it isn't in conflict with the state I live in. The state can do the same as long as it doesn't violate the laws of the country it is in.&lt;br /&gt;&lt;br /&gt;Although not normally thought of in that sense, my home does have legal rights, restrictions, and regulations that I apply to my household. I don't allow coloring on the walls. If one does so, they know that their crayons will be taken away, and they will lose allowance for the next two weeks or perhaps certain video game privileges, depending on the age of the perpetrator.&lt;br /&gt;&lt;br /&gt;Now in the past, if I wanted one of my children to have a computer, I'd buy/build/whatever a computer, and install all the necessary software I think they need, as well as any other software that they desire that I don't deem as contraband.&lt;br /&gt;&lt;br /&gt;However with the GPLv3, if I compile together components for a computer, as well as various software into a nice personal computer, if any of the software is GPLv3, I can't restrict any other previous legal rights to the user of this personal computer.&lt;br /&gt;&lt;br /&gt;Buying children expensive gifts have always been a form of negotiation and a method to apply new restrictions on troublesome issues that have recently come up. For example, if my daughter recently decided she wanted earings, but her mother and I decided we don't want her to get her ears pierced right now, we'd try to negotiate the restriction. If we knew she also wanted a nice new laptop, we'd perhaps buy her the laptop, but make a deal with her, that if she uses this nice new pink Eee PC, she no longer asks her mother and I if she can have earings until she is 16. This way she can be content about having a new computer, and wont bring up her desire for earings for a few more years.&lt;br /&gt;&lt;br /&gt;However, if we got her an Eee PC with Linux installed with several GPLv3 apps, as opposed to the Windows preinstalled Eee PC, we would not be allowed to under the terms of the GPLv3 negotiate this agreement with our daughter.&lt;br /&gt;&lt;br /&gt;It seems because of the GPLv3, I can't give my children anything but Windows on the computers I buy for them, if I try to use them as a bargaining chip. Before you Mac lovers pounce on me, please recall that MacBooks today come with GCC, which is GPLv3.&lt;br /&gt;&lt;br /&gt;Thanks to the GPLv3, it seems now Windows is the only Operating System that is right for your family. Remember also to be careful which open source applications you preload with, to make sure they aren't GPLv3.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/833174317742362874-2540523401286659863?l=insanecoding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://insanecoding.blogspot.com/feeds/2540523401286659863/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=833174317742362874&amp;postID=2540523401286659863' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/833174317742362874/posts/default/2540523401286659863'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/833174317742362874/posts/default/2540523401286659863'/><link rel='alternate' type='text/html' href='http://insanecoding.blogspot.com/2008/12/gplv3-is-it-right-for-your-family.html' title='GPLv3 - Is it right for your family?'/><author><name>insane coder</name><uri>http://www.blogger.com/profile/06901386115570670209</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-833174317742362874.post-3375070617397178755</id><published>2008-09-09T08:14:00.000-07:00</published><updated>2008-09-09T17:41:25.914-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='bugs'/><category scheme='http://www.blogger.com/atom/ns#' term='binary'/><category scheme='http://www.blogger.com/atom/ns#' term='searching'/><category scheme='http://www.blogger.com/atom/ns#' term='school'/><category scheme='http://www.blogger.com/atom/ns#' term='sorting'/><category scheme='http://www.blogger.com/atom/ns#' term='tree'/><title type='text'>Binary Trees - Does it matter?</title><content type='html'>Ever programmed a Binary Tree before? If you took computer science classes past an introductory level, you probably studied the theory before. But to what extent do decisions matter?&lt;br /&gt;&lt;br /&gt;To review for those of you who don't quite recall what a binary tree is. You have a series of nodes, each node contains data, some or all of which is the key, up to two pointers to children nodes, and possibly other meta data. The most popular type of binary tree is the &lt;a href="http://en.wikipedia.org/wiki/Binary_search_tree"&gt;Binary Search Tree&lt;/a&gt;, where each node conceptually has nodes with lesser keys descending on the left, and nodes with greater keys descending on the right.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_vLES3KKBdaM/SMb5Hza5cdI/AAAAAAAAADE/oaVZTBPYqDA/s1600-h/bt1.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://1.bp.blogspot.com/_vLES3KKBdaM/SMb5Hza5cdI/AAAAAAAAADE/oaVZTBPYqDA/s320/bt1.png" alt="" id="BLOGGER_PHOTO_ID_5244152728576946642" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;How to implement a left and right can be done with two node pointers called left and right, lesser and greater, an array of two node pointers, or any other method which makes sense to you.&lt;br /&gt;&lt;br /&gt;All operations begin with the topmost node in the figure above, known as the root, head, or top node of the tree. To find a node with a particular key, one compares it against the current node, if it found it good, otherwise, if it's less, take the left route, otherwise the right. If there is no path left or right as requested, since there is only a null pointer there, then a node with a matching key is not in the tree. At each node reached, the same algorithm is applied. In this instance, a Binary Tree is very similar to Binary Search, each check effectively cuts the data in half, leading to very efficient searches.&lt;br /&gt;&lt;br /&gt;Adding data to a tree is very much the same. The data is encapsulated in a node, which again goes down the tree finding where the data should belong, in this case, once a null pointer is encountered while trying to traverse the tree further, it is replaced by a pointer to the new node.&lt;br /&gt;&lt;br /&gt;Deleting data can be a bit trickier. If a node has no children, deleting a node is quite straight forward. If the node only has a path left or right, one simply cuts out the node being deleted, and makes the pointer once pointing to it now point to the child. However, for removing a node which has two children descending from it, there's a number of methods that can be applied.&lt;br /&gt;&lt;br /&gt;The simplest method is to make one child a replacement, and add the other child onto the child replacing, meaning add the left node to the right or the right to the left.&lt;br /&gt;&lt;br /&gt;Look what happens when deleting the root node, which in this case has two children.&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_vLES3KKBdaM/SMb5ILKdc3I/AAAAAAAAADM/915UpB5icZ0/s1600-h/bt2.png"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; text-align: center; cursor: pointer;" src="http://2.bp.blogspot.com/_vLES3KKBdaM/SMb5ILKdc3I/AAAAAAAAADM/915UpB5icZ0/s320/bt2.png" alt="" id="BLOGGER_PHOTO_ID_5244152734950454130" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_vLES3KKBdaM/SMb5IdX4HPI/AAAAAAAAADU/3CbTQxQBOwE/s1600-h/bt3.png"&gt;&lt;img style="margin: 0pt 10px; float: right; text-align: center; cursor: pointer;" src="http://2.bp.blogspot.com/_vLES3KKBdaM/SMb5IdX4HPI/AAAAAAAAADU/3CbTQxQBOwE/s320/bt3.png" alt="" id="BLOGGER_PHOTO_ID_5244152739838565618" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;The node with a key of 50 is deleted which had two children, 25 and 100. Either 25 becomes the new root, with 100 as the rightmost of 25's descendants, or 100 becomes the new root, with 25 as the leftmost of 100's descendants.&lt;br /&gt;&lt;br /&gt;The only problem with this algorithm is that it can quickly make the tree become unbalanced, degrading into a linked list. A tree should be as close to balanced as possible, so search or addition can be done with cutting half the tree out per each node looked at. An unbalanced tree would make each operation generally consist of looking at most of the nodes in the tree, which is inefficient.&lt;br /&gt;&lt;br /&gt;Therefore, the generally proposed algorithm is to find the next or previous node by key, and move it to replace the node being deleted. First lest us understand tree order.&lt;br /&gt;&lt;br /&gt;A binary tree can be processed in direct order using the following algorithm.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;function process_node(Node *node)&lt;br /&gt;{&lt;br /&gt;  if (node-&gt;has_left()) { process_node(node-&gt;left()); }&lt;br /&gt;  process_node_data(node-&gt;data());&lt;br /&gt;  if (node-&gt;has_right()) { process_node(node-&gt;right()); }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Which is plain English means handle left, then current, then right, in a recursive fashion. Because a Binary Tree can be processed in this fashion, in addition to being a nice data structure, it can also be used as the basis of a sorting algorithm. All data is encapsulated in a node and is added to the tree, then it is traversed in order as just described, placing the data back into the original data structure, and then the tree is destroyed.&lt;br /&gt;&lt;br /&gt;Now understanding this, the node prior to any particular node in regards to its key is always one left, and then rightmost, and the node after a particular key is one right, and then left most.&lt;br /&gt;&lt;br /&gt;And the delete:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_vLES3KKBdaM/SMb5IcI4Z_I/AAAAAAAAADc/cR25eBl5VA0/s1600-h/bt5.png"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; text-align: center; cursor: pointer;" src="http://2.bp.blogspot.com/_vLES3KKBdaM/SMb5IcI4Z_I/AAAAAAAAADc/cR25eBl5VA0/s320/bt5.png" alt="" id="BLOGGER_PHOTO_ID_5244152739507234802" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_vLES3KKBdaM/SMb5IX-9NxI/AAAAAAAAADk/MDUD_kbrCqw/s1600-h/bt6.png"&gt;&lt;img style="margin: 0pt 10px; float: right; text-align: center; cursor: pointer;" src="http://3.bp.blogspot.com/_vLES3KKBdaM/SMb5IX-9NxI/AAAAAAAAADk/MDUD_kbrCqw/s320/bt6.png" alt="" id="BLOGGER_PHOTO_ID_5244152738391865106" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;50 is deleted, and the previous or next one takes its place. In this case, 35 being the previous, and 75 being the next one.&lt;br /&gt;&lt;br /&gt;Now to get to the meat of the article, &lt;span style="font-style: italic;"&gt;does it matter&lt;/span&gt;? Does what matter?&lt;br /&gt;&lt;br /&gt;First off, we didn't at all mention how to handle nodes which have equivalent keys. Back when I was in college learning computer science, we were told to just throw it down the right or the left, but be consistent about it. Also, when it comes to deleting, take the previous or the next, but again, it doesn't matter, as long as one was consistent about it. Or perhaps in this latter case, alternate sides per delete.&lt;br /&gt;&lt;br /&gt;But the question we must ask is: &lt;span style="font-weight: bold;"&gt;"&lt;span style="font-style: italic;"&gt;Does it matter&lt;/span&gt;?"&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;And the answer which they at the very least didn't teach me when I was in school, yes, it does matter!&lt;br /&gt;&lt;br /&gt;When one sorts, one can do a &lt;a href="http://en.wikipedia.org/wiki/Sorting_algorithm#Stability"&gt;stable&lt;/a&gt; or an unstable sort. Stable means that if two elements had equivalent keys, when sorting, the order of those nodes would be preserved. Meaning if we had: "50 C, 45 A, 23 C, 50 B, 75 D, 50 A", and the numbers would make up the key, but not the letters, then it would sort to: "23 C, 45 A, 50 C, 50 B, 50 A, 75 D", keeping the order of C,B,A among the elements with a key of 50. Unstable would mean that the relative order of those 50s is not guaranteed to be kept when sorting.&lt;br /&gt;&lt;br /&gt;A binary tree can only be used as a stable sort if equal data is always placed on the right side. This is because the order of succession is left, current, right, and if it was placed on the left, it would mean the node added later came before the current node.&lt;br /&gt;&lt;br /&gt;What not to do:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_vLES3KKBdaM/SMb5bYUrPPI/AAAAAAAAADs/wKM41kSlYgI/s1600-h/bt7.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; cursor: pointer;" src="http://1.bp.blogspot.com/_vLES3KKBdaM/SMb5bYUrPPI/AAAAAAAAADs/wKM41kSlYgI/s320/bt7.png" alt="" id="BLOGGER_PHOTO_ID_5244153064900476146" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;However, just putting equal data on the right isn't the end of the matter yet. Most good Binary Trees, such as a &lt;a href="http://en.wikipedia.org/wiki/Red_black_tree"&gt;Red &amp;amp; Black Tree&lt;/a&gt; will implement some kind of self balancing system, so areas which are starting to become linked lists rotate to become balanced trees.&lt;br /&gt;&lt;br /&gt;Looks like a linked list:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_vLES3KKBdaM/SMb5bk4jFHI/AAAAAAAAAD0/2Eq_LDEvgNs/s1600-h/bt8.png"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://2.bp.blogspot.com/_vLES3KKBdaM/SMb5bk4jFHI/AAAAAAAAAD0/2Eq_LDEvgNs/s320/bt8.png" alt="" id="BLOGGER_PHOTO_ID_5244153068272161906" border="0" /&gt;&lt;/a&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_vLES3KKBdaM/SMb5bjzOwNI/AAAAAAAAAEE/iEjMojNe7zY/s1600-h/bt10.png"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://1.bp.blogspot.com/_vLES3KKBdaM/SMb5bjzOwNI/AAAAAAAAAEE/iEjMojNe7zY/s320/bt10.png" alt="" id="BLOGGER_PHOTO_ID_5244153067981422802" border="0" /&gt;&lt;/a&gt;&lt;div style="text-align: left;"&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_vLES3KKBdaM/SMb5boAVk2I/AAAAAAAAAD8/-SvHOw1wpMc/s1600-h/bt9.png"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://4.bp.blogspot.com/_vLES3KKBdaM/SMb5boAVk2I/AAAAAAAAAD8/-SvHOw1wpMc/s320/bt9.png" alt="" id="BLOGGER_PHOTO_ID_5244153069110137698" border="0" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;As can be seen in the diagrams, the middle node of the three becomes the new parent of the section with the first node becoming the left. This still follows the in order rules of left, center, right, because the one of the left is indeed the first node. And rotations like this, would also preserve numbering orders of the keys (otherwise a Red &amp; Black Tree or another self balancing tree would never employ them).&lt;br /&gt;&lt;br /&gt;Now adding another 50 on our proposed case still works with our initially stated algorithm, we traverse down till we reach our area of 50s, then place it to the right of the right most one. However, we have to slightly rewrite our find a node which matches a key algorithm. If we want our tree to always return the first node which matches a key, or in the case of deletion, delete the first node which matches a key, one can't just search until one finds a matching node, since it in fact may be the second or third node if rotations took place. Rather, one has check to see if the left contains the same value, and if so, go left most across matching keys, and return the deepest one found there.&lt;br /&gt;&lt;br /&gt;Now after reviewing these revised rules, is your binary tree written properly? Furthermore, have you ever even seen an implementation which when searching checks left most for matching keys?&lt;br /&gt;&lt;br /&gt;Oh, and before we leave, what about deleting, does it matter if the prior or the next node is chosen? The other night, a student of mine asked me that, and presented to me a case which we both agreed proved that to properly delete and keep a stable sort, one has to use the next node, and not the prior one to properly preserve the key order. Although, we were both tired at the time, and now when trying to recreate the case I can't seem to do it. So I do hope I was in error the other night, and am not leaving out a crucial point. If you happen to know of a case where it matters, please describe it in the comments.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/833174317742362874-3375070617397178755?l=insanecoding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://insanecoding.blogspot.com/feeds/3375070617397178755/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=833174317742362874&amp;postID=3375070617397178755' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/833174317742362874/posts/default/3375070617397178755'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/833174317742362874/posts/default/3375070617397178755'/><link rel='alternate' type='text/html' href='http://insanecoding.blogspot.com/2008/09/binary-trees-does-it-matter.html' title='Binary Trees - Does it matter?'/><author><name>insane coder</name><uri>http://www.blogger.com/profile/06901386115570670209</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_vLES3KKBdaM/SMb5Hza5cdI/AAAAAAAAADE/oaVZTBPYqDA/s72-c/bt1.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-833174317742362874.post-9017738936866129124</id><published>2008-01-29T21:53:00.000-08:00</published><updated>2008-01-29T23:26:39.110-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='KDE'/><category scheme='http://www.blogger.com/atom/ns#' term='Mozilla'/><category scheme='http://www.blogger.com/atom/ns#' term='Windows'/><category scheme='http://www.blogger.com/atom/ns#' term='Firefox'/><title type='text'>Mozilla is the new Microsoft</title><content type='html'>So who here loves Mozilla and their browsers such as Firefox?&lt;br /&gt;&lt;br /&gt;I do too, but am I the only one finding Mozilla turning more into Microsoft every day?&lt;br /&gt;&lt;br /&gt;To start off, lets point fingers at the memory issue. Notice how Windows' memory requirements have gone through the roof? Yet comparable desktop environments and windowing systems from other sources seem to be just as advanced as Microsoft's latest offering and don't use a fraction of the RAM. I'm told KDE 4 runs comfortably with only 512MB of RAM, and you can even get away with 256MB, while a friend of mine running Vista started with 1.5GB but said he had to add another 512MB so the system didn't get all slugish on him. Does Vista offer anything special that KDE 4 doesn't?&lt;br /&gt;&lt;br /&gt;Compare that to Firefox these days. I open up Firefox with two tabs, one in a pretty ordinary text page with a single image on it, and another with some tables and a form, and it uses over 400MB of RAM. When mentioning it to Mozilla, they of course tell you it's a feature not a bug (sound familiar?). What feature exactly needs all that RAM? I'm told some nonsense about how it caches previous pages one went to, so they load quickly when you press back. Considering I just opened the browser, which pages is it caching exactly?&lt;br /&gt;&lt;br /&gt;To further compound my bafflement of the issue, I even disabled that feature in about:config, and yet Firefox still eats a ton of RAM when I open it. I used to run Netscape Navigator on a machine with 16MB of RAM, and two whole browser windows opened, and it didn't eat a fraction of the RAM Firefox does now (and this was before Windows had virtual memory). Heck, even other web browsers such as Konqueror and Opera don't use that much.&lt;br /&gt;&lt;br /&gt;Well, now you'll tell me, but at least Firefox started the whole standards revolution right? At least it's better than Internet Explorer, right?&lt;br /&gt;&lt;br /&gt;While it's true that it's better than IE, I wouldn't even consider IE a browser, as it can't even get basic standards right. If you had a program which edited text files, and you have it open a file, and it comes up with paragraphs out of order, and some not even appearing, would you call it a text editor? Yet I'm starting to see Gecko (the engine powering Firefox and Seamonkey) go the same route. Try setting a background for a radio button with CSS in Firefox, it completely ignores it. Yet even IE, the non-webbrowser, can do CSS backgrounds for radio buttons (albeit it only changes the background color outside the radio button itself within its rendering square).&lt;br /&gt;&lt;br /&gt;This gets worse when trying to couple some JavaScript with your pages in Firefox. The onchange event for select boxes only fires in Firefox when changing them with the keyboard when one presses enter. All other browsers fire the event as soon as you can see a change within the box, such as when one presses up or down. Now perhaps you'll tell me that's undefined behavior so Firefox can implement it differently than everyone else (sound like Microsoft any?), but now apply this to how it handles dynamic text. Say you want to take our example above and convert your onchange in a select box to an onkeydown, so it should fire for every up/down request in the box without the user needing to press enter. Firefox again fails completely here, since it won't update text on a page modified by JavaScript till the screen is clicked, or a button is pressed. Meaning if you have your onkeydown event for a select box call a function which changes some text on the page, to say perhaps the contents of that select box. You won't actually see those changes till you press a button, perhaps up or down again, showing you the previous value on your page from the select box, instead of the current one. Sounds like a real stellar browser, doesn't it?&lt;br /&gt;&lt;br /&gt;Then there's the issue about how Mozilla is trying to make their browser the only platform out there. Why do most people today still use Windows, even when there's a better OS for the average person? It all boils down to the applications. Anyone who is proposed to switch asks, can I play my favorite games on this other OS? Does my digital camera's photo sorting software work on it? What about all the other applications that I use on a regular basis? As Microsoft's chief primate keeps yelling, it's all about the developers. People will be stuck using whatever runs their favorite apps.&lt;br /&gt;&lt;br /&gt;Now of course we know that the internet in many ways is becoming the new platform out there, hence why Microsoft tried to crush it or control it all these years. So as long as your browser is standards compliant, if people develop for it, we should be okay, no?&lt;br /&gt;&lt;br /&gt;Unfortunately it's not like that. GMail doesn't work on Konqueror unless Konqueror changes its user agent to report as Gecko. Meaning many sites lock out browsers just because they didn't test with them, not because it doesn't work for any particular reason. A similar problem exists how IIS servers gibberish to browsers reporting themself as Opera. Yet Microsoft only wants to keep it that way.&lt;br /&gt;&lt;br /&gt;Recently Microsoft reported that the upcoming IE 8 will only go into standard compliance mode when websites include an IE8 tag in their code. Now most people who discussed this feature have totally missed the main problem. It's not about having to add an extra tag. It's that the default mode for any whacko out there writing a webpage is to render in IE 6 or IE 7 super-bug-filled-non-standards-compliant-mode, so webpages will continue to not become standardized. Of course Microsoft realizes this, they'll do everything they can to make sure the large majority of stuff coming out by the clueless masses only works on their platform.&lt;br /&gt;&lt;br /&gt;Now I'm not talking about Mozilla making the web buggy like Microsoft is trying to (but I bet they'd like that if they could get away with it), but it's that they're trying to get people dependent on their web browser. How so? It's all about the &lt;b&gt;&lt;i&gt;extensions&lt;/i&gt;&lt;/b&gt;!&lt;br /&gt;Mozilla invented their own language and format and ranted and raved about how everyone should be writing extensions for their browser, and how their browser is the de-facto standard of the free world.&lt;br /&gt;&lt;br /&gt;How many of you using Firefox feel they need all kinds of extras that people write for it? How often do you sit down at someone else's Firefox and feel naked about a lack of certain features you tailored your browser back home or at work to?&lt;br /&gt;&lt;br /&gt;Now while I could go on and on about all kinds of extensions, everyone has their own tastes, so it'd be pointless to, but I'll point out a couple of examples.&lt;br /&gt;&lt;br /&gt;Some of the extensions I use regularly for Firefox, such as auto translations of pages in languages I don't read/speak, or user agent spoofing are built right into Konqueror, many others aren't available anywhere else, or only for certain browsers written specifically for them. I'm talking about the GMail/Yahoo/And whatever else e-mail notifiers that can tell you when you received new e-mail, or ForcastFox which can tell me mostly accurate weather info for the week for just about anywhere in the world.&lt;br /&gt;&lt;br /&gt;Now these extensions I just mentioned are perhaps not anything to get addicted to, but what about Ad blocking? Now of course other browsers also have a Mozilla compatible ad block framework installed, how many of them allow you to install something like the "Filterset.G Updater" so you can have your blacklists automatically updated by others to hide all the new types of ads on the internet that come out, such as the "Download Firefox Ad" that appears on the right of this page?&lt;br /&gt;&lt;br /&gt;Not only that, we can hardly forget the wide plethora of developer related things one can get for Firefox, such as JavaScript Console, DOM Inspector, and all the extensions such as the Web Developer Toolbar and who knows what else.&lt;br /&gt;&lt;br /&gt;Am I the only one who now feels locked into Firefox and can't switch because their special browser software doesn't run elsewhere? Even when we realize what a horrible wreck Firefox is, and terrible on machines with little RAM available?&lt;br /&gt;&lt;br /&gt;Furthermore, you know how Microsoft always forces their desires upon you? Take this picture of Bill Gates for example:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_vLES3KKBdaM/R6AWswUsxCI/AAAAAAAAAC8/eoI8UjPxlk0/s1600-h/bill_gates_400.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://2.bp.blogspot.com/_vLES3KKBdaM/R6AWswUsxCI/AAAAAAAAAC8/eoI8UjPxlk0/s320/bill_gates_400.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5161150131108365346" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Notice how his own personal desktop is the default Windows XP background? Surely a man as technical as Bill Gates can figure out how to change it to something he enjoys, just like everyone else has.&lt;br /&gt;Or perhaps Bill Gates never changed it, since the &lt;i&gt;default&lt;/i&gt; Windows XP background was Bill Gates' personal background at the time? Of course leave it to a guy like him to force his personal desires on everyone else.&lt;br /&gt;&lt;br /&gt;Now lets see how Mozilla does the exact same thing. Ever wondered where Firefox's logo came from? Who would think that an image of a fox conquering the world is a good logo for a browser?&lt;br /&gt;&lt;br /&gt;Check out a picture of Mozilla's former CEO, Mitchell Baker:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_vLES3KKBdaM/R6AU0AUsxBI/AAAAAAAAAC0/KcJKIR-e_J0/s1600-h/people-mitchell-baker2.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://3.bp.blogspot.com/_vLES3KKBdaM/R6AU0AUsxBI/AAAAAAAAAC0/KcJKIR-e_J0/s320/people-mitchell-baker2.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5161148056639161362" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Now what do you think came first, the Firefox logo? Or her ridiculous hair cut?&lt;br /&gt;Still don't get what I mean? See this:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_vLES3KKBdaM/R6AT5gUsxAI/AAAAAAAAACs/_LZQlMU19E8/s1600-h/ff-ceo.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://1.bp.blogspot.com/_vLES3KKBdaM/R6AT5gUsxAI/AAAAAAAAACs/_LZQlMU19E8/s320/ff-ceo.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5161147051616814082" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;If you think you can point out how Mozilla isn't the Microsoft of the internet platform, please let me know, I'd love to hear how you came to your false conclusions.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/833174317742362874-9017738936866129124?l=insanecoding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://insanecoding.blogspot.com/feeds/9017738936866129124/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=833174317742362874&amp;postID=9017738936866129124' title='11 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/833174317742362874/posts/default/9017738936866129124'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/833174317742362874/posts/default/9017738936866129124'/><link rel='alternate' type='text/html' href='http://insanecoding.blogspot.com/2008/01/mozilla-is-new-microsoft.html' title='Mozilla is the new Microsoft'/><author><name>insane coder</name><uri>http://www.blogger.com/profile/06901386115570670209</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_vLES3KKBdaM/R6AWswUsxCI/AAAAAAAAAC8/eoI8UjPxlk0/s72-c/bill_gates_400.jpg' height='72' width='72'/><thr:total>11</thr:total></entry><entry><id>tag:blogger.com,1999:blog-833174317742362874.post-2879301978545609085</id><published>2008-01-28T00:34:00.000-08:00</published><updated>2008-01-28T01:57:48.725-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='open source'/><category scheme='http://www.blogger.com/atom/ns#' term='KDE'/><category scheme='http://www.blogger.com/atom/ns#' term='Trolltech'/><category scheme='http://www.blogger.com/atom/ns#' term='Library'/><category scheme='http://www.blogger.com/atom/ns#' term='API'/><category scheme='http://www.blogger.com/atom/ns#' term='binary'/><category scheme='http://www.blogger.com/atom/ns#' term='Windows'/><category scheme='http://www.blogger.com/atom/ns#' term='Qt'/><category scheme='http://www.blogger.com/atom/ns#' term='Portability'/><category scheme='http://www.blogger.com/atom/ns#' term='closed source'/><title type='text'>Say goodbye to the former Qt and hello to MiniQt?</title><content type='html'>So everyone knows that Nokia is looking to buy Trolltech, the company behind Qt right? If not, read the &lt;a href="http://trolltech.com/company/newsroom/announcements/press.2008-01-28.4605718236"&gt;press release&lt;/a&gt;.&lt;br /&gt;Trolltech also has up a &lt;a href="http://trolltech.com/28012008/28012008"&gt;list&lt;/a&gt; of what this means for everyone, as well as a &lt;a href="http://trolltech.com/28012008/28012008-letter"&gt;letter to the open source community&lt;/a&gt; (rename it to .pdf).&lt;br /&gt;&lt;br /&gt;Now after hearing all that, you're probably running in one of two directions. Either thinking that "oh no, my Qt has been taken over by an evil organization and it'll be destroyed!", or that "KDE and Trolltech have an agreement over Qt so we're safe!". The interesting point is that both are true.&lt;br /&gt;&lt;br /&gt;What? Both are true?!?! How can that be?&lt;br /&gt;&lt;br /&gt;First, a little background. Qt which is the foundation of KDE, and what all the pillars of KDE stand on, is pretty much irreplaceable. Not wanting to ever get bitten by developing such a massive project on such a foundation controlled by a company, KDE and Trolltech signed an agreement, and formed a new group called the "&lt;a href="http://www.kde.org/whatiskde/kdefreeqtfoundation.php"&gt;KDE Free Qt Foundation&lt;/a&gt;".&lt;br /&gt;&lt;br /&gt;To put it in their own words:&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;To fulfill the purpose of the Foundation, an agreement between Trolltech and the Foundation was made. This gives the Foundation the right to release Qt under a BSD-style license in case Trolltech doesn't continue the development of the Qt Free Edition for any reason including, but not limited to, a buy-out of Trolltech, a merger or bankruptcy.&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;As for the latest agreement, you can find links to it on their site, but the primary part to worry about is &lt;a href="http://www.kde.org/whatiskde/images/agreement3.png"&gt;this&lt;/a&gt;. Let me summarize. If 12 months have passed without seeing an open source release of Qt, or the open source version falls behind the closed source one in that period of time, or the board as a whole (which half is composed of by Trolltech) agrees to release Qt as BSD, then it shall take the latest open source version of Qt, and open source it under the BSD license as they will become legally able to.&lt;br /&gt;&lt;br /&gt;Now one must wonder why is that important? The current release is under GPL2/3 anyway, why do we need to have it stuck under BSD? We can always continue using the latest release as GPL2/3.&lt;br /&gt;&lt;br /&gt;The great thing about Qt is that they have a corporation backing it, making sure the toolkit is excellent. They pay employees to do all the dirty and annoying work in the library too. They also ensure that it remains portable on a large variety of hardware. This kind of heavy work is not something the open source community is usually able to coordinate too well. There are very few large open source projects that are fully portable, run on greatly varied setups, and cover areas that most people don't want to program for. For example, Ubuntu made a release a while back where a significant portion of printer support was broken, since it's not fun to test or fix, there's nothing really challenging about printer support (except maybe getting those annoying devices to work in the first place, and not paper jamming), and it's not cost effective to make sure it continues to work, and the "save the universe, time, and pluto" groups wouldn't like you using all that paper either.&lt;br /&gt;&lt;br /&gt;Also, Qt is currently able to be gotten either via a proprietary license or under the GPL (with exceptions too!), so companies producing closed source software, and open source nutjobs can play on equal footing. That means when a company hires a developer to develop with Qt, it's the same Qt, so s/he can later go home and use his or her knowledge to write a cool new open source application involving giraffes e-mailing pictures of people with dyed hair around, or whatever s/he might fancy. It also means that open source developers who want to create their own startup company, can use the knowledge they already gathered to write terrific applications, since they can just go and buy some licenses, and write their new apps.&lt;br /&gt;&lt;br /&gt;The "Poison Pill" that they signed on would put Qt under BSD, which would continue to allow the companies, and the communities to continue to work with the same software, in the event that Trolltech became evil (or by extension of being bought). It could also mean that a company could throw developers at Qt, and use stuff privately in their own products too, and not be forced to not be allowed to do anything with their own changes, since it's virally all GPL.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;This all falls apart however when one considers precisely what is in the agreement. IFF ('If and only if', for those of you who missed school that day), Trolltech or the new company fails to deliver an open source version or equal to the version offered proprietarily for an extended period of time, they can BSD what they have. This is great as long as the evil company doesn't continue to offer something which is worthless to the community but not so to the companies.&lt;br /&gt;&lt;br /&gt;To quote Nokia:&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;We will continue to actively develop Qt and Qtopia. We also want to underline that we will continue to support the open source community by continuing to release these technologies under the GPL&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;Lets step back and think for a moment what Nokia is interested in. Cell Phones, right? Meaning only Qtopia, Qt in itself is worthless to them. Also consider what Trolltech's primary business is. They advertise &lt;a href="http://trolltech.com/customers/coolapps"&gt;these applications&lt;/a&gt; as the coolest using Qt. How many of those applications are done by those who buy a license? Now once you figured that out, how many of those have anything other than a Windows build? Many companies use Qt, not for the portability, but because of how easy it is. Here, &lt;a href="http://trolltech.com/customers/coolapps/adobe"&gt;read what Adobe&lt;/a&gt;, a company who has never produced Linux software, has to say. Since companies use it for the ease of use, and speed of development time, and don't really care if it works on Linux or not, since we all know that those Linux guys don't buy anything anyway, why should Nokia bother continuing to develop the X11 port of Qt? It's just a waste of time for any normal business model.&lt;br /&gt;&lt;br /&gt;So Nokia could continue to develop Qt for their cellphones, and for customers such as Adobe, and even release Windows only, or perhaps even Windows and Mac OS X builds of Qt both proprietary and under the GPL, but none for X11. And what can the "KDE Free Qt Foundation" do about it anyway? Their agreement is worthless as there can still be an open source version which won't be useful to most of their developers. And who in the world are they going to complain to about 'intent' of the agreement? KDE runs on Windows and Mac OS X now, right? Their petty foundation can continue making their Kool Desktop Environment as long as it's done on Windows right? No one is stopping them.&lt;br /&gt;&lt;br /&gt;At this point, the companies and the communities can be fractured, and even worse if the library is very different one platform to the next, it will become completely worthless for the sake of portability. Having an unfunded fork off of an older Qt won't do as well either, just look at what an awful mess the crippled broken GTK is, even with it being LGPL so companies can use it - if they were drugged up enough to.&lt;br /&gt;&lt;br /&gt;On the other hand, Qtopia does run on Linux, but isn't protected by the KDE foundation either. If Nokia for whatever reason continued releasing Qtopia under open source, and the X11 port died, but cool new features of equal footing came to the Windows/OS X/Qtopia ports, perhaps the community might get some movement in the direction of moving away from the horrible X11. Bleh, who am I kidding, the nightmare that is X11 is here to stay, right?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/833174317742362874-2879301978545609085?l=insanecoding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://insanecoding.blogspot.com/feeds/2879301978545609085/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=833174317742362874&amp;postID=2879301978545609085' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/833174317742362874/posts/default/2879301978545609085'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/833174317742362874/posts/default/2879301978545609085'/><link rel='alternate' type='text/html' href='http://insanecoding.blogspot.com/2008/01/say-goodbye-to-former-qt-and-hello-to.html' title='Say goodbye to the former Qt and hello to MiniQt?'/><author><name>insane coder</name><uri>http://www.blogger.com/profile/06901386115570670209</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-833174317742362874.post-9010940766380959905</id><published>2008-01-23T19:45:00.000-08:00</published><updated>2008-01-23T21:29:23.963-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='KDE'/><category scheme='http://www.blogger.com/atom/ns#' term='File Dialog'/><category scheme='http://www.blogger.com/atom/ns#' term='directory'/><category scheme='http://www.blogger.com/atom/ns#' term='Dolphin'/><category scheme='http://www.blogger.com/atom/ns#' term='Windows'/><category scheme='http://www.blogger.com/atom/ns#' term='GUI'/><title type='text'>KDE 4 Review - Insane Style</title><content type='html'>So KDE 4 is out, along with major architectural changes, a new face, and new software, as well as tweaks to what KDE 3 had.&lt;br /&gt;&lt;br /&gt;Now if you wanted to know about all the new libraries, and new platforms supported, or kinds of other flashy changes they made, you can look elsewhere on the internet. Instead I'm going to just describe the changes to the standard file open dialog, and the ramifications of having Dolphin as the new file manager, keeping in tradition of the &lt;a href="http://insanecoding.blogspot.com/2007/04/file-dialogs-take-2.html"&gt;previous&lt;/a&gt; &lt;a href="http://insanecoding.blogspot.com/2007/03/file-dialogs.html"&gt;file dialog&lt;/a&gt; articles.&lt;br /&gt;&lt;br /&gt;So without further babbling, here's the new file open dialog:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_vLES3KKBdaM/R5gKrwUsw6I/AAAAAAAAAB8/nrFSoQ25JLo/s1600-h/kde4-fd.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://2.bp.blogspot.com/_vLES3KKBdaM/R5gKrwUsw6I/AAAAAAAAAB8/nrFSoQ25JLo/s320/kde4-fd.png" alt="" id="BLOGGER_PHOTO_ID_5158885119975277474" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Now ignoring all styling issues for the time being, let us compare that to what KDE 3.5 did:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_vLES3KKBdaM/Rf0zU88WMXI/AAAAAAAAAAc/b0j7rp8OX4o/s1600-h/fileopen3.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://1.bp.blogspot.com/_vLES3KKBdaM/Rf0zU88WMXI/AAAAAAAAAAc/b0j7rp8OX4o/s320/fileopen3.png" alt="" id="BLOGGER_PHOTO_ID_5043243592774463858" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;First big difference is that the KDE 4 file dialog now has a crumb view on top. The crumb view is nice, in that if you want to jump back up a few directories, you can do so in a single click, instead of pressing up multiple times. &lt;br /&gt;&lt;br /&gt;In fact you don't even need an up button anymore, but don't worry, the design experts at KDE gave you one anyway, since space on that line isn't important. Because if it was important they might consider moving the encoding drop down elsewhere - oh wait they did do that.&lt;br /&gt;&lt;br /&gt;You've got to love mixed messages when it comes to GUI design, they needed more room for the crumb browser so they moved the encoding elsewhere to take up a full line down below, yet leave in the up button. Also interesting to note that KDE 4 is now using Qt 4, which quite nicely offers a file system watcher for paths to tell when they get updated to automatically refresh a file view, it seems despite that, the KDE team thinks you also need a nice refresh button on top.&lt;br /&gt;&lt;br /&gt;Now if they really wanted to manage space properly, perhaps they'd put the crumb navigation on a line by itself up top, instead of giving all that room to encoding drop down which doesn't need a fraction of the room it's getting. Maybe something along the lines of this mockup I just made in KolourPaint:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_vLES3KKBdaM/R5gRgwUsw9I/AAAAAAAAACU/Dop8bMejetA/s1600-h/kde4-fd-mockup.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://2.bp.blogspot.com/_vLES3KKBdaM/R5gRgwUsw9I/AAAAAAAAACU/Dop8bMejetA/s320/kde4-fd-mockup.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5158892627578110930" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Now there's plenty of room for large paths for the crumb browser, and no ridiculously huge encoding selector.&lt;br /&gt;&lt;br /&gt;But these obvious issues aside, we haven't even gone past the surface of how utterly useless the dialog has become.&lt;br /&gt;&lt;br /&gt;Remember how I spoke about how Windows added annoying virtual locations? Seems KDE copied them down the last annoying detail. Now "/home/insane" appears as "Home" in the crumb viewer (and no absolute path anywhere). If I want to go up to "/home", and then "/home/spouse", it's impossible. "Home" is treated as a root path, even to the extent that the unneeded up button doesn't do anything at this point either. One has to click on the left on "Root", then select "/home". This gets worse if you're on a machine where home directories are stored several levels deep. Of course power users, can type in the full path in the location bar on the bottom, but you'd think a group as intelligent as KDE can avoid glaring Windows design flaws. Don't even get me started on what happens if you delete the Root button from the quick locations on the left. Poor users who want to find someone else's home directory now have to navigate through the root path filled with stuff like "usr", "opt", "bin", "srv", and other unintelligent gibberish to do something that once was a single button click.&lt;br /&gt;&lt;br /&gt;And speaking of annoying locations. Why the heck is Trash a location that appears by default in the quick locations? How often do you decide that the document you need to open is in the trash? I'm glad they removed Desktop, but replacing it with Trash? What were they thinking? Give me something useful like a Media quick link, for optical drives and all kinds of USB/Firewire external memory devices. They also completely removed support for right clicking on the quick locations panel, and just adding a new quick location. Now one is forced to drag a directory's folder icon from the right to the left. I wonder how that will work if one is in some kind of virtual directory that has no parent, making it impossible to drag.&lt;br /&gt;&lt;br /&gt;Anyways regarding other features, remember how KDE 3 gave the user a lot of power and allowed them to have something similar to the old Windows 3 split view?&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_vLES3KKBdaM/R5gTVwUsw_I/AAAAAAAAACk/yySIH1GMy4U/s1600-h/kde3-fds.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://2.bp.blogspot.com/_vLES3KKBdaM/R5gTVwUsw_I/AAAAAAAAACk/yySIH1GMy4U/s320/kde3-fds.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5158894637622805490" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;For some reason this useful method to navigate your files is completely gone.&lt;br /&gt;And now with the old location input bar merged into the one for files, I can't even easily edit the current location by hand, since it doesn't display the current path at all. Furthermore, entering a new path seems to make it have useless data left over in it like the last path directory component after enter is pressed.&lt;br /&gt;&lt;br /&gt;Old KDE file browser: 10&lt;br /&gt;New KDE file browser: 6&lt;br /&gt;&lt;br /&gt;I guess making the perfect file browser, especially when you were almost there is next to impossible.&lt;br /&gt;&lt;br /&gt;Speaking of file browsers, lets look at how the new edition of Dolphin fares, touted as being better than Konqueror for simple management of files.&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_vLES3KKBdaM/R5gKsAUsw7I/AAAAAAAAACE/jDINsNaomeg/s1600-h/kde4-dol.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://3.bp.blogspot.com/_vLES3KKBdaM/R5gKsAUsw7I/AAAAAAAAACE/jDINsNaomeg/s320/kde4-dol.png" alt="" id="BLOGGER_PHOTO_ID_5158885124270244786" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;Now I remember I complained to some KDE devs a while back regarding the KDE 4 betas and how Dolphin seemed to be a bit brain damaged at file management, but they assured me it would change for the final release of KDE 4.0, and change it did! For the worse.&lt;br /&gt;&lt;br /&gt;Back in the older betas, one could click a button to bring up a full path editor instead of the crumb view, now that button is completely gone. To bring it up, one has to go browse through one of the menus on top to switch back and forth between the quick browsing methods.&lt;br /&gt;&lt;br /&gt;Here too, they also kept the brain damaged virtual Home path. There is no way to go up. Nice to see they didn't put in a useless up button, but here again, if I want to see everyone's home directory, I have to navigate there from Root.&lt;br /&gt;&lt;br /&gt;Also, if one switches to the classic path editor, if one wants to go up, they're forced to backspace the old path, or switch back to the crumb view, since in the KDE Dolphin developers' great vision, they couldn't stick both views in at the same time, or make an up button appear when in the classic path editor.&lt;br /&gt;&lt;br /&gt;There's also no nice directory and file split view here like good ol' File Manager. But one can bring up a directory tree browser:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_vLES3KKBdaM/R5gKsAUsw8I/AAAAAAAAACM/enkfoD94rWw/s1600-h/kde4-dol2.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://3.bp.blogspot.com/_vLES3KKBdaM/R5gKsAUsw8I/AAAAAAAAACM/enkfoD94rWw/s320/kde4-dol2.png" alt="" id="BLOGGER_PHOTO_ID_5158885124270244802" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;And in keeping with the new KDE 4 design goal of copying stupidity from Windows (Vista), when viewing the tree view, the file viewing pane is also filled with now redundant directory listings.&lt;br /&gt;&lt;br /&gt;Isn't it wonderful to see how people who used to be way ahead of the curve and tried so hard to offer a really advanced product have completely fell between the cracks when it came to normal sane usability of files?&lt;br /&gt;&lt;br /&gt;For those of you wondering if perhaps GTK got any better since the last time I reviewed it, you can rest assured that it has not. In fact, I now have a new refined hatred for how lousy GTK is. In the course of uploading some images from FireFox in an article I was writing, the GTK file menu had the file type filter locked to (*.png/*.bmp/*.gif/*.jpg/*.jpeg). Since the pictures I had were all *.JPG, none showed up, as GTK in their infinite wisdom made the extension filter case sensitive.&lt;br /&gt;&lt;br /&gt;Seems UNIX file management is just as lousy as ever and getting worse. I'm afraid to even look at Konqueror in KDE 4, fearing they ruined it too.&lt;br /&gt;&lt;br /&gt;Feel free to start a flame war in the comments, I got my flame retardant suit on, besides nothing you can write can make me feel worse than what a downgrade KDE went through.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/833174317742362874-9010940766380959905?l=insanecoding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://insanecoding.blogspot.com/feeds/9010940766380959905/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=833174317742362874&amp;postID=9010940766380959905' title='15 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/833174317742362874/posts/default/9010940766380959905'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/833174317742362874/posts/default/9010940766380959905'/><link rel='alternate' type='text/html' href='http://insanecoding.blogspot.com/2008/01/kde-4-review-insane-style.html' title='KDE 4 Review - Insane Style'/><author><name>insane coder</name><uri>http://www.blogger.com/profile/06901386115570670209</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_vLES3KKBdaM/R5gKrwUsw6I/AAAAAAAAAB8/nrFSoQ25JLo/s72-c/kde4-fd.png' height='72' width='72'/><thr:total>15</thr:total></entry><entry><id>tag:blogger.com,1999:blog-833174317742362874.post-5205403580341881657</id><published>2007-11-11T05:30:00.001-08:00</published><updated>2007-11-11T13:54:31.197-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='getcwd'/><category scheme='http://www.blogger.com/atom/ns#' term='Library'/><category scheme='http://www.blogger.com/atom/ns#' term='opendir'/><category scheme='http://www.blogger.com/atom/ns#' term='readdir'/><category scheme='http://www.blogger.com/atom/ns#' term='save_cwd'/><category scheme='http://www.blogger.com/atom/ns#' term='file descriptor'/><category scheme='http://www.blogger.com/atom/ns#' term='PATH_MAX'/><category scheme='http://www.blogger.com/atom/ns#' term='fstatat'/><category scheme='http://www.blogger.com/atom/ns#' term='gnu'/><category scheme='http://www.blogger.com/atom/ns#' term='API'/><category scheme='http://www.blogger.com/atom/ns#' term='buffer overflow'/><category scheme='http://www.blogger.com/atom/ns#' term='directory'/><category scheme='http://www.blogger.com/atom/ns#' term='stat'/><category scheme='http://www.blogger.com/atom/ns#' term='openat'/><category scheme='http://www.blogger.com/atom/ns#' term='Portability'/><category scheme='http://www.blogger.com/atom/ns#' term='realpath'/><title type='text'>Directory safety when working with paths</title><content type='html'>As we discussed in our &lt;a href="http://insanecoding.blogspot.com/2007/11/implementing-realpath-in-c.html"&gt;previous&lt;/a&gt; &lt;a href="http://insanecoding.blogspot.com/2007/11/pathmax-simply-isnt.html"&gt;two&lt;/a&gt; articles, we run into issues of thread safety when we try changing the path during a running program. Therefor, in addition to bypassing PATH_MAX problems, working around buffer issues thanks to implementing with C++, we would also love to implement our functions without ever calling chdir() and changing the working directory. We'll now look into how we can make changes to our implementation to avoid a chdir() call, along with the pros and cons of techniques UNIX operating systems provide us, as well as what they're lacking.&lt;br /&gt;&lt;br /&gt;If one looks back at how we implemented getcwd(), they'll notice that we call chdir("..") for each step in our loop. We need this to sanitize the location for these three calls:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;opendir(".")&lt;br /&gt;lstat(entry-&gt;d_name, &amp;sb)&lt;br /&gt;stat(".", &amp;sb)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;To remove the need of changing directories, we can place the ".." paths directly into our calls to opendir(), lstat(), and stat(). Thanks to C++ Strings being dynamic, it makes it easy for us to manipulate paths for these situations properly. We'll also see that being clever, we can even avoid string manipulation for some of these cases. And if our OSs supplied enough functionality, without any string manipulation at all!&lt;br /&gt;&lt;br /&gt;Here's how we can implement getcwd() based off our previous implementation, but without calls to chdir(), with key details highlighted:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;bool getcwd(std::string&amp; path)&lt;br /&gt;{&lt;br /&gt;  typedef std::pair&amp;lt;dev_t, ino_t&amp;gt; file_id;&lt;br /&gt;&lt;br /&gt;  bool success = false;&lt;br /&gt;  struct stat sb;&lt;br /&gt;  if (!stat(".", &amp;sb))&lt;br /&gt;  {&lt;br /&gt;    file_id current_id(sb.st_dev, sb.st_ino);&lt;br /&gt;    if (!stat("/", &amp;sb)) //Get info for root directory, so we can determine when we hit it&lt;br /&gt;    {&lt;br /&gt;      std::vector&amp;lt;std::string&amp;gt; path_components;&lt;br /&gt;      file_id root_id(sb.st_dev, sb.st_ino);&lt;br /&gt;      &lt;span style="color:#E1771E;"&gt;std::string up_path("..");&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;      while (current_id != root_id) //If they're equal, we've obtained enough info to build the path&lt;br /&gt;      {&lt;br /&gt;        bool pushed = false;&lt;br /&gt;        DIR *dir = opendir(up_path.c_str());&lt;br /&gt;        if (dir)&lt;br /&gt;        {&lt;br /&gt;          dirent *entry;&lt;br /&gt;          &lt;span style="color:#E1771E;"&gt;up_path += "/";&lt;/span&gt;&lt;br /&gt;          &lt;span style="color:#E1771E;"&gt;std::string::size_type after_slash = up_path.size();&lt;/span&gt;&lt;br /&gt;          while ((entry = readdir(dir))) //We loop through each entry trying to find where we came from&lt;br /&gt;          {&lt;br /&gt;            if (strcmp(entry-&gt;d_name, ".") &amp;&amp; strcmp(entry-&gt;d_name, ".."))&lt;br /&gt;            {&lt;br /&gt;              &lt;span style="color:#E1771E;"&gt;up_path.replace(after_slash, std::string::npos, entry-&gt;d_name);&lt;/span&gt;&lt;br /&gt;              if (!&lt;span style="color:#E1771E;"&gt;lstat(up_path.c_str(), &amp;sb)&lt;/span&gt;)&lt;br /&gt;              {&lt;br /&gt;                file_id child_id(sb.st_dev, sb.st_ino);&lt;br /&gt;                if (child_id == current_id) //We found where we came from, add its name to the list&lt;br /&gt;                {&lt;br /&gt;                  path_components.push_back(entry-&gt;d_name);&lt;br /&gt;                  pushed = true;&lt;br /&gt;                  break;&lt;br /&gt;                }&lt;br /&gt;              }&lt;br /&gt;            }&lt;br /&gt;          }&lt;br /&gt;&lt;br /&gt;          if (pushed &amp;&amp; !&lt;span style="color:#E1771E;"&gt;fstat(dirfd(dir), &amp;sb)&lt;/span&gt;) //If we have a reason to contiue, we update the current dir id&lt;br /&gt;          {&lt;br /&gt;            current_id = file_id(sb.st_dev, sb.st_ino);&lt;br /&gt;            &lt;span style="color:#E1771E;"&gt;up_path.replace(after_slash, std::string::npos, ".."); &lt;/span&gt;//Keep recursing towards root each iteration&lt;br /&gt;          }&lt;br /&gt;&lt;br /&gt;          &lt;span style="color:#E1771E;"&gt;closedir(dir);&lt;/span&gt;&lt;br /&gt;        }&lt;br /&gt;        if (!pushed) { break; } //If we didn't obtain any info this pass, no reason to continue&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;      if (current_id == root_id) //Unless they're equal, we failed above&lt;br /&gt;      {&lt;br /&gt;        //Built the path, will always end with a slash&lt;br /&gt;        path = "/";&lt;br /&gt;        for (std::vector&amp;lt;std::string&amp;gt;::reverse_iterator i = path_components.rbegin(); i != path_components.rend(); ++i)&lt;br /&gt;        {&lt;br /&gt;          path += *i+"/";&lt;br /&gt;        }&lt;br /&gt;        success = true;&lt;br /&gt;      }&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  return(success);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;First of all, we removed all the code related to saving the current directory when we started, since we don't need that information anymore. Our first major change is that we created a new C++ String called up_path, we'll use this variable to keep track of the path, initializing it to "..". then for each step through the loop, make it "../..", "../../.." and so on, till we reach the root. We use this to replace our calls to opendir() to "." as we were doing before.&lt;br /&gt;At this point, we'll add a slash to the path, and keep track of the spot with the variable after_slash. Now in our read directory loop, we can replace whatever is after the slash with the filename in the directory to pass to lstat(), again bypassing the need to be in the same directory as the file when making the function call.&lt;br /&gt;Now for the stat() call on the directory itself, we got a little interesting. Instead of doing a path manipulation trick again, we call fstat() on the file descriptor returned from dirfd() on the already open directly handle. Notice how the call to close directory has been moved to after the block of code, so the directory is still open. And of course it's all wrapped up nicely with appending ".." after the slash.&lt;br /&gt;&lt;br /&gt;Noticing how we eliminated path manipulation for the last part, it would be nice to eliminate more of it, especially if anyone wants to port this C++ code to C. The good news is that on Solaris and Linux we can, and as soon as the "at" functions get standardized, we can use them on the other UNIX OSs too. You can read more about them in one of our previous articles, &lt;a href="http://insanecoding.blogspot.com/2007/03/file-descriptors-and-why-we-cant-use.html"&gt;File Descriptors and why we can't use them&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Here's how we can use the at functions to eliminate the path manipulation needed for calling lstat(), with the differences highlighted:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;bool getcwd(std::string&amp; path)&lt;br /&gt;{&lt;br /&gt;  typedef std::pair&amp;lt;dev_t, ino_t&amp;gt; file_id;&lt;br /&gt;&lt;br /&gt;  bool success = false;&lt;br /&gt;  struct stat sb;&lt;br /&gt;  if (!stat(".", &amp;sb))&lt;br /&gt;  {&lt;br /&gt;    file_id current_id(sb.st_dev, sb.st_ino);&lt;br /&gt;    if (!stat("/", &amp;sb)) //Get info for root directory, so we can determine when we hit it&lt;br /&gt;    {&lt;br /&gt;      std::vector&amp;lt;std::string&amp;gt; path_components;&lt;br /&gt;      file_id root_id(sb.st_dev, sb.st_ino);&lt;br /&gt;      std::string up_path("..");&lt;br /&gt;&lt;br /&gt;      while (current_id != root_id) //If they're equal, we've obtained enough info to build the path&lt;br /&gt;      {&lt;br /&gt;        bool pushed = false;&lt;br /&gt;        DIR *dir = opendir(up_path.c_str());&lt;br /&gt;        if (dir)&lt;br /&gt;        {&lt;br /&gt;          &lt;span style="color:#E1771E;"&gt;int dir_fd = dirfd(dir);&lt;/span&gt;&lt;br /&gt;          dirent *entry;&lt;br /&gt;          while ((entry = readdir(dir))) //We loop through each entry trying to find where we came from&lt;br /&gt;          {&lt;br /&gt;            if (strcmp(entry-&gt;d_name, ".") &amp;&amp; strcmp(entry-&gt;d_name, "..") &amp;&amp; !&lt;span style="color:#E1771E;"&gt;fstatat(dir_fd, entry-&gt;d_name, &amp;sb, AT_SYMLINK_NOFOLLOW)&lt;/span&gt;)&lt;br /&gt;            {&lt;br /&gt;              file_id child_id(sb.st_dev, sb.st_ino);&lt;br /&gt;              if (child_id == current_id) //We found where we came from, add its name to the list&lt;br /&gt;              {&lt;br /&gt;                path_components.push_back(entry-&gt;d_name);&lt;br /&gt;                pushed = true;&lt;br /&gt;                break;&lt;br /&gt;              }&lt;br /&gt;            }&lt;br /&gt;          }&lt;br /&gt;&lt;br /&gt;          if (pushed &amp;&amp; !&lt;span style="color:#E1771E;"&gt;fstat(dir_fd, &amp;sb)&lt;/span&gt;) //If we have a reason to contiue, we update the current dir id&lt;br /&gt;          {&lt;br /&gt;            current_id = file_id(sb.st_dev, sb.st_ino);&lt;br /&gt;            &lt;span style="color:#E1771E;"&gt;up_path += "/..";&lt;/span&gt; //Keep recursing towards root each iteration&lt;br /&gt;          }&lt;br /&gt;&lt;br /&gt;          closedir(dir);&lt;br /&gt;        }&lt;br /&gt;        if (!pushed) { break; } //If we didn't obtain any info this pass, no reason to continue&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;      if (current_id == root_id) //Unless they're equal, we failed above&lt;br /&gt;      {&lt;br /&gt;        //Built the path, will always end with a slash&lt;br /&gt;        path = "/";&lt;br /&gt;        for (std::vector&amp;lt;std::string&amp;gt;::reverse_iterator i = path_components.rbegin(); i != path_components.rend(); ++i)&lt;br /&gt;        {&lt;br /&gt;          path += *i+"/";&lt;br /&gt;        }&lt;br /&gt;        success = true;&lt;br /&gt;      }&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  return(success);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;As should be easily discernible, the string manipulation got easier, and mostly vanished. All the keeping track of a slash, and replaces has been replaced with only needing to append "/.." at the end of each loop.&lt;br /&gt;Instead of manipulating a path string for our call to lstat(), we save the directory's file descriptor above (and subsequently use that instead of recalculating it lower down for fstat()), then use it to get the lstat() for each file in the directory, but now via fstatat().&lt;br /&gt;fstatat() is the same as stat()/lstat(), but takes a directory descriptor as the first parameter to offset where the filename is relative to. The last parameter can be 0 or AT_SYMLINK_NOFOLLOW, which makes it act like stat() or lstat() respectively. fstatat() instead of a file descriptor can also take the special value AT_FDCWD to have it automatically work in the current directory.&lt;br /&gt;&lt;br /&gt;This implementation should be much more elegant, but a bit less portable. If one would like to implement fstatat() themselves, it's not hard, here's how you can do it:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;int fstatat(int dirfd, const char *pathname, struct stat *buf, int flags)&lt;br /&gt;{&lt;br /&gt;  int success = -1;&lt;br /&gt;&lt;br /&gt;  if ((!flags || (flags == AT_SYMLINK_NOFOLLOW)))&lt;br /&gt;  {&lt;br /&gt;    int cwdfd = -1;&lt;br /&gt;    if ((dirfd == AT_FDCWD) || (pathname &amp;&amp; (*pathname == '/')) || (((cwdfd=open(".", O_RDONLY)) != -1) &amp;&amp; !fchdir(dirfd)))&lt;br /&gt;    {&lt;br /&gt;      success = (!flags) ? stat(pathname, buf) : lstat(pathname, buf);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    if (cwdfd != -1)&lt;br /&gt;    {&lt;br /&gt;      fchdir(cwdfd);&lt;br /&gt;      close(cwdfd);&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;  else&lt;br /&gt;  {&lt;br /&gt;    errno = EINVAL;&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  return(success);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;You'll also need the defines for AT_FDCWD and AT_SYMLINK_NOFOLLOW. You have to make sure that the value you choose for AT_FDCWD can't be a valid file descriptor or the normal failure return value. Therefor I chose -2 in my implementations, but choosing any negative value should be okay.  AT_SYMLINK_NOFOLLOW shouldn't matter what it is, and a value of 1 or for all I care, 42, should be fine.&lt;br /&gt;If your OS supports the at functions (currently Linux 2.6.16+ and recent versions of Solaris), it's better not to use a custom implementation, as this isn't thread safe, since it calls fchdir() internally, and for our example, runs counter to the whole point of using fstatat(). It would also be faster to use the original getcwd() implementation from a few days ago than using an emulated fstatat(), since there's less overhead from repeated fchdir() calls.&lt;br /&gt;It's also interesting to note that glibc on Linux now, even for older than 2.6.16 implements fstatat() and the whole slew of at functions even when not supported in the Kernel. It's similar to ours, can be thread unsafe due to changing the working directory, and for some inexplicable reason, segfaulted in certain circumstances when I ran a large battery of tests on it and my implementation against the Kernel's to make sure that mine was working properly.&lt;br /&gt;&lt;br /&gt;Anyways, with that out of the way, one can't hope but wonder if it would be possible to also eliminate the need of any path string manipulation for the call to opendir(). Mysteriously, neither Solaris nor Linux have an opendirat() call. If there was such, we could easily keep the previous directory open, till we obtained a new handle for its parent directory.&lt;br /&gt;Baring having an opendirat() function, it'd be nice to implement such a thing. Some UNIX OSs I understand have a function perhaps named fopendir() or fdopendir() to promote a file descriptor to a directory handle. With such a function, we can simply write an opendirat() which calls openat(), then promotes it, but Linux doesn't have a method of promotion, although Solaris does (fdopendir()). Lets hope the people who are standardizing the new at functions for POSIX seriously consider what they're doing, otherwise &lt;a href="http://insanecoding.blogspot.com/2007/03/file-descriptors-and-why-we-cant-use.html"&gt;we won't be able to use them&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Now that we've gotten getcwd() to be safe, we still need realpath() to be. In our realpath() implementation, the only unsafe parts was our function chdir_getcwd() which called chdir() internally as well as getcwd(). getcwd() is now taken care of, but we still need to rewrite the rest of chdir_getcwd() to not actually chdir().&lt;br /&gt;To do such should now be easy, we simply do getcwd(), but with a new start path. We'd make a new function called getcwd_internal() which would take two parameters, one for the current directory, and another to initialize the up one, which we can wrap everything else around. Basically copy your favorite getcwd(), but make the modifications to the beginning like so:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;bool getcwd_internal(std::string&amp; path, const std::string&amp; start_dir, std::string&amp; up_path)&lt;br /&gt;{&lt;br /&gt;  typedef std::pair&amp;lt;dev_t, ino_t&amp;gt; file_id;&lt;br /&gt;&lt;br /&gt;  bool success = false;&lt;br /&gt;  struct stat sb;&lt;br /&gt;  if (!stat(start_dir.c_str(), &amp;sb))&lt;br /&gt;  {&lt;br /&gt;    file_id current_id(sb.st_dev, sb.st_ino);&lt;br /&gt;    if (!stat("/", &amp;sb)) //Get info for root directory, so we can determine when we hit it&lt;br /&gt;    {&lt;br /&gt;      std::vector&amp;lt;std::string&amp;gt; path_components;&lt;br /&gt;      file_id root_id(sb.st_dev, sb.st_ino);&lt;br /&gt;&lt;br /&gt;      while (current_id != root_id) //If they're equal, we've obtained enough info to build the path&lt;br /&gt;--SNIP--&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Now we'd turn getcwd() and chdir_getcwd() into wrappers like so:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;bool getcwd(std::string&amp; path)&lt;br /&gt;{&lt;br /&gt;  std::string up_path("..");&lt;br /&gt;  return(getcwd_internal(path, ".", up_path));&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;bool chdir_getcwd(const std::string&amp; dir, std::string&amp; path)&lt;br /&gt;{&lt;br /&gt;  std::string up_path(dir+"/..");&lt;br /&gt;  return(getcwd_internal(path, dir, up_path));&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Note that the name of chdir_getcwd() is now misleading that it doesn't actually change directories anymore. For this reason, it's a good idea to not put any implementation details into a function name, as a user shouldn't have to know about them, and over time, it can become inaccurate.&lt;br /&gt;&lt;br /&gt;And there you have it folks, getcwd() and realpath() implemented safely. Hopefully in the process all you loyal readers learned a couple other things too.&lt;br /&gt;&lt;br /&gt;Other improvements over all we discussed, might be to run a smart pass over concatenated path names at key locations to remove extra slashes together "///", unneeded current directory "/./", and extra parent directories "path1/path2/.." -&gt; "path1/", which is useful if certain functions like opendir() or the stat() family of calls have internal buffer issues. But doing such is a discussion for another time.&lt;br /&gt;&lt;br /&gt;This wraps up our long discussion. All comments and suggestions are welcome.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/833174317742362874-5205403580341881657?l=insanecoding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://insanecoding.blogspot.com/feeds/5205403580341881657/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=833174317742362874&amp;postID=5205403580341881657' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/833174317742362874/posts/default/5205403580341881657'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/833174317742362874/posts/default/5205403580341881657'/><link rel='alternate' type='text/html' href='http://insanecoding.blogspot.com/2007/11/directory-safety-when-working-with.html' title='Directory safety when working with paths'/><author><name>insane coder</name><uri>http://www.blogger.com/profile/06901386115570670209</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-833174317742362874.post-7009200953982692931</id><published>2007-11-09T04:04:00.000-08:00</published><updated>2007-11-10T09:25:13.230-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='getcwd'/><category scheme='http://www.blogger.com/atom/ns#' term='Function Pointers'/><category scheme='http://www.blogger.com/atom/ns#' term='Library'/><category scheme='http://www.blogger.com/atom/ns#' term='save_cwd'/><category scheme='http://www.blogger.com/atom/ns#' term='file descriptor'/><category scheme='http://www.blogger.com/atom/ns#' term='PATH_MAX'/><category scheme='http://www.blogger.com/atom/ns#' term='open source'/><category scheme='http://www.blogger.com/atom/ns#' term='API'/><category scheme='http://www.blogger.com/atom/ns#' term='buffer overflow'/><category scheme='http://www.blogger.com/atom/ns#' term='directory'/><category scheme='http://www.blogger.com/atom/ns#' term='secure'/><category scheme='http://www.blogger.com/atom/ns#' term='BSD'/><category scheme='http://www.blogger.com/atom/ns#' term='standards compliance'/><category scheme='http://www.blogger.com/atom/ns#' term='Portability'/><category scheme='http://www.blogger.com/atom/ns#' term='Optimization'/><category scheme='http://www.blogger.com/atom/ns#' term='realpath'/><title type='text'>Implementing realpath() in C++</title><content type='html'>Before reading this post, please read the background in the previous post &lt;a href="http://insanecoding.blogspot.com/2007/11/pathmax-simply-isnt.html"&gt;PATH_MAX simply isn't&lt;/a&gt;, as it covers important background, and has some code we'll be building on over here.&lt;br /&gt;&lt;br /&gt;Here's what realpath() is supposed to do:&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;realpath() expands all symbolic links and resolves references to ’/./’, ’/../’ and extra ’/’ characters in the null terminated string named by path and stores the canonicalized absolute pathname in the buffer of size PATH_MAX named by resolved_path. The resulting path will have no symbolic link, ’/./’ or ’/../’ components.&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;Instead of attacking implementing such a thing head on, we'll take a bottom up approach. One should consider that being able to break down a path between the path components prior to the last slash and after the last slash is essential to figuring out which directory the file actually lies.&lt;br /&gt;&lt;br /&gt;The built in functions for this are called dirname() and basename(), but they modify their arguments, and they do some funny handling in special cases which we don't want.&lt;br /&gt;&lt;br /&gt;So to implement our own for our purposes, we can write a function as follows:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;void relative_dir_base_split(const std::string&amp; path, std::string&amp; dir, std::string&amp; base)&lt;br /&gt;{&lt;br /&gt;  std::string::size_type slash_pos = path.rfind("/"); //Find the last slash&lt;br /&gt;  if (slash_pos != std::string::npos) //If there is a slash&lt;br /&gt;  {&lt;br /&gt;    slash_pos++;&lt;br /&gt;    dir = path.substr(0, slash_pos); //Directory is before slash&lt;br /&gt;    base = path.substr(slash_pos); //And obviously, the file is after&lt;br /&gt;  }&lt;br /&gt;  else //Otherwise, there is no directory present&lt;br /&gt;  {&lt;br /&gt;    dir.clear(); &lt;br /&gt;    base = path;&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The function is simple enough, pass it a path, and two C++ strings for the return values, and have it split them up.&lt;br /&gt;&lt;br /&gt;The next function which we'll use is one to get the realpath() of a directory. We can easily get such a thing by chdir()'ing to the directory, running our getcwd(), and then chdir() back.&lt;br /&gt;This simple function is as follows:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;bool chdir_getcwd(const std::string&amp; dir, std::string&amp; path)&lt;br /&gt;{&lt;br /&gt;  bool success = false;&lt;br /&gt;  int start_fd = open(".", O_RDONLY); //Open current directory so we can save a handle to it&lt;br /&gt;  if (start_fd != -1)&lt;br /&gt;  {&lt;br /&gt;    if (!chdir(dir.c_str())) //Change to directory&lt;br /&gt;    {&lt;br /&gt;      success = getcwd(path); //And get its path&lt;br /&gt;      fchdir(start_fd); //And change back of course&lt;br /&gt;    }&lt;br /&gt;    close(start_fd);&lt;br /&gt;  }&lt;br /&gt;  return(success);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;This simple function to resolve where a directory is located uses should be obvious, however, it's also a core function in figuring our where a file is, since a file is located at the realpath() of its parent directory, plus the base name for the file itself.&lt;br /&gt;&lt;br /&gt;Now to get the realpath() of a file, we have this simple wrapper over the above functions:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;static inline bool realpath_file(const std::string&amp; path, std::string&amp; resolved_path)&lt;br /&gt;{&lt;br /&gt;  bool success = false;&lt;br /&gt;  std::string dir;&lt;br /&gt;  std::string base;&lt;br /&gt;  relative_dir_base_split(path, dir, base);&lt;br /&gt;&lt;br /&gt;  //If there is a directory, get the realpath() for it, otherwise the current directory&lt;br /&gt;  if (dir.size() ? chdir_getcwd(dir, resolved_path) : getcwd(resolved_path))&lt;br /&gt;  {&lt;br /&gt;    resolved_path += base;&lt;br /&gt;    success = true;&lt;br /&gt;  }&lt;br /&gt;  return(success);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Now we have chdir_getcwd() which is basically a realpath() for a directory, and realpath_file() for files. Note however, that if you call realpath_file() directly, it won't actually ensure that the file exists, so probably a bad idea to call directly, unless you don't care if it exists or not. It also won't handle symlinks. To handle symlinks we need quite a bit more code.&lt;br /&gt;&lt;br /&gt;First, let us write a wrapper in C++ for reading links:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;bool readlink_internal(const std::string&amp; path, std::string&amp; buffer, ssize_t length)&lt;br /&gt;{&lt;br /&gt;  bool success = false;&lt;br /&gt;  if (length &gt; 0)&lt;br /&gt;  {&lt;br /&gt;    char *buf = new(nothrow) char[length+1]; //Room for Null&lt;br /&gt;    if (buf)&lt;br /&gt;    {&lt;br /&gt;      ssize_t amount = ::readlink(path.c_str(), buf, length+1); //Give room for failure&lt;br /&gt;      if ((amount &gt; 0) &amp;&amp; (amount &lt;= length)) //If &gt; length, it was modified mid check&lt;br /&gt;      {&lt;br /&gt;        buf[amount] = 0;&lt;br /&gt;        buffer = buf;&lt;br /&gt;        success = true;&lt;br /&gt;      }&lt;br /&gt;      delete[] buf;&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;  return(success);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;This function simply wraps up the built in one, and uses C++ strings for dynamic allocation, so we don't have to worry about it directly in our function to resolve symlinks.&lt;br /&gt;&lt;br /&gt;Before diving into the actual details in resolving a symlink, let me present one more helper function:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;void build_path_base_swap(std::string &amp;path, const std::string&amp; newbase)&lt;br /&gt;{&lt;br /&gt;  string dir;&lt;br /&gt;  string base;&lt;br /&gt;  relative_dir_base_split(path, dir, base);&lt;br /&gt;&lt;br /&gt;  if (dir.size())&lt;br /&gt;  {&lt;br /&gt;    path = dir + newbase;&lt;br /&gt;  }&lt;br /&gt;  else&lt;br /&gt;  {&lt;br /&gt;    path = newbase;&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;This above function will take a path, and replace the base part of it, meaning if you pass it "path/cows.txt" and "feet.txt", path will become "path/feet.txt".&lt;br /&gt;&lt;br /&gt;Now onto the symlink discussion.&lt;br /&gt;&lt;br /&gt;Resolving symlinks in itself is hard though, since one symlink could lead to another, meaning we'll need a loop. We also need to defend ourselves against an infinite loop if one symlink links to itself, or a symlink earlier on in our resolve loop.&lt;br /&gt;&lt;br /&gt;It is not safe enough to call a regular stat() to check for the final link existing (and not a loop), since during our resolve, an attacker can modify a link, so we have to detect that.&lt;br /&gt;Unfortunately, most OSs/libraries have a define called MAXSYMLINKS which I've seen set anywhere from 8 to 30. They stop their loop once they've iterated MAXSYMLINKS times and return an errno of ELOOP. Unfortunately, doing such has two flaws, which I hope should be apparent. First of all, if a link links to itself immediately, it would take MAXSYMLINKS passes until the function finally realizes it (I'm looking at you OpenBSD). The other issue is that it's just wrong.&lt;br /&gt;Hopefully any of us who has taken a data structures course would know that there are algorithms for detecting a loop in a linked list, and not have to resort to any dumb method which doesn't actually detect a loop. Also a number such as 8 is way too low which I've seen some do
