{"id":62,"date":"2011-12-29T14:14:00","date_gmt":"2011-12-29T14:14:00","guid":{"rendered":"https:\/\/sandrock.co.za\/carl\/2011\/12\/29\/the-fallacy-of-the-general-purpose-tool\/"},"modified":"2011-12-29T14:14:00","modified_gmt":"2011-12-29T14:14:00","slug":"the-fallacy-of-the-general-purpose-tool","status":"publish","type":"post","link":"https:\/\/sandrock.co.za\/carl\/2011\/12\/the-fallacy-of-the-general-purpose-tool\/","title":{"rendered":"The fallacy of the general purpose tool"},"content":{"rendered":"<p>I carry a Leatherman on my belt every day wherever I go.  It has become a bit of an extension of my body, which I only really notice when I have to fly somewhere and I&#8217;m forced to take it off for the flight.  Then I get to my destination and I can&#8217;t open the cable ties on my luggage.  At the same time, I have a whole pinboard of tools up in my garage, which overlap somewhat with my Leatherman: a dedicated set of pliers, some dedicated screwdrivers and scissors and so on.  This is because the is not as good as any of these dedicated tools.<\/p>\n<div><\/div>\n<div>I think the same goes for programming languages, and therefore I have learned quite a few, just like I have stocked my pinboard with tools that do one thing very well.  Many people find learning new languages onerous and will try to find the one language that does everything they want to do well. Their arguments against learning a new language often involves something like &#8220;but I can do that just fine in my language, and then I don&#8217;t have to learn a new language&#8221;.  Here&#8217;s an example from real life that illustrates the advantages of special purpose languages.<\/div>\n<div><\/div>\n<div>My father approaches me with this problem.  He uses an accounting package which can import <a href=\"http:\/\/www.ofx.net\/\">OFX files<\/a> (they&#8217;re an SGML\/XML format for financial records), but there is a slight problem.  The ZAR needs to be changed to USD and the dates (which are tags of the form 20111201 &#8211; yes, no closing tag as it&#8217;s SGML) have to be changed from YYYYMMDD to YYYYDDMM. Now, turns out that Python has a nice OFX module.  So does <a href=\"http:\/\/ofx4j.sourceforge.net\/\">Java<\/a>.  But the fastest way to make the changes to his files is probably sed:<\/div>\n<div>\n<pre>sed -r -i -e 's\/ZAR\/USD\/' -e 's\/&lt;DT(.*)&gt;<dt><dt>([0-9]{4})([0-9]{2})([0-9]{2})\/&lt;DT1&gt;243\/' filename.ocx<\/dt><\/dt><\/pre>\n<p>This does the replacement in-place, is really fast and is quick enough to throw together.  This is the kind of thing that sed shines at.  In fact, it is exactly what it was designed to do, so it is unsurprising that it does it so well.<\/p><\/div>\n<div><\/div>\n<div>To do the same thing in Python (even without using the OFX module) requires a bit more effort:<\/div>\n<div><\/div>\n<p><\/p>\n<pre style='color:#000000;background:#ffffff'><span style='color:#800000;font-weight:bold'>import<\/span> os<br \/><span style='color:#800000;font-weight:bold'>import<\/span> re<br \/><span style='color:#800000;font-weight:bold'>from<\/span> tempfile <span style='color:#800000;font-weight:bold'>import<\/span> mkstemp<br \/><br \/>filename <span style='color:#808030'>=<\/span> <span style='color:#0000e6'>\"test.txt\"<\/span><br \/>patternStrings <span style='color:#808030'>=<\/span> <span style='color:#808030'>[<\/span><span style='color:#0000e6'>\"ZAR\"<\/span><span style='color:#808030'>,<\/span> <span style='color:#0000e6'>r\"&lt;TD([^&gt;]+)&gt;([0-9]{4})([0-9]{2})([0-9]{2})\"<\/span><span style='color:#808030'>]<\/span><br \/>replacements <span style='color:#808030'>=<\/span> <span style='color:#808030'>[<\/span><span style='color:#0000e6'>\"USD\"<\/span><span style='color:#808030'>,<\/span> <span style='color:#0000e6'>r\"&lt;TD1&gt;243\"<\/span><span style='color:#808030'>]<\/span><br \/><br \/><span style='color:#696969'># Compile patterns<\/span><br \/>patterns <span style='color:#808030'>=<\/span> <span style='color:#808030'>[<\/span>re<span style='color:#808030'>.<\/span><span style='color:#e34adc'>compile<\/span><span style='color:#808030'>(<\/span>p<span style='color:#808030'>)<\/span> <span style='color:#800000;font-weight:bold'>for<\/span> p <span style='color:#800000;font-weight:bold'>in<\/span> patternStrings<span style='color:#808030'>]<\/span><br \/><br \/><span style='color:#696969'># Create temporary file to hold outputs<\/span><br \/>_<span style='color:#808030'>,<\/span> tempfile <span style='color:#808030'>=<\/span> mkstemp<span style='color:#808030'>(<\/span><span style='color:#808030'>)<\/span><br \/><br \/><span style='color:#696969'># Process file<\/span><br \/>outfile <span style='color:#808030'>=<\/span> <span style='color:#e34adc'>open<\/span><span style='color:#808030'>(<\/span>tempfile<span style='color:#808030'>,<\/span> <span style='color:#0000e6'>'w'<\/span><span style='color:#808030'>)<\/span><br \/><span style='color:#800000;font-weight:bold'>for<\/span> line <span style='color:#800000;font-weight:bold'>in<\/span> <span style='color:#e34adc'>open<\/span><span style='color:#808030'>(<\/span>filename<span style='color:#808030'>)<\/span><span style='color:#808030'>:<\/span><br \/>    <span style='color:#800000;font-weight:bold'>for<\/span> pattern<span style='color:#808030'>,<\/span> replacement <span style='color:#800000;font-weight:bold'>in<\/span> zip<span style='color:#808030'>(<\/span>patterns<span style='color:#808030'>,<\/span> replacements<span style='color:#808030'>)<\/span><span style='color:#808030'>:<\/span><br \/>        line <span style='color:#808030'>=<\/span> pattern<span style='color:#808030'>.<\/span>sub<span style='color:#808030'>(<\/span>replacement<span style='color:#808030'>,<\/span> line<span style='color:#808030'>)<\/span><br \/>    outfile<span style='color:#808030'>.<\/span>write<span style='color:#808030'>(<\/span>line<span style='color:#808030'>)<\/span><br \/><br \/>outfile<span style='color:#808030'>.<\/span>close<span style='color:#808030'>(<\/span><span style='color:#808030'>)<\/span><br \/><br \/>os<span style='color:#808030'>.<\/span>rename<span style='color:#808030'>(<\/span>tempfile<span style='color:#808030'>,<\/span> filename<span style='color:#808030'>)<\/span><br \/><\/pre>\n<p><\/p>\n<div>Needless to say, the difference is even more pronounced in Java due to the large amount of boilerplate needed.<\/div>\n<div>\n<pre style='color:#000000;background:#ffffff'><span style='color:#800000;font-weight:bold'>import<\/span><span style='color:#004a43'> java<\/span><span style='color:#808030'>.<\/span><span style='color:#004a43'>io<\/span><span style='color:#808030'>.<\/span><span style='color:#004a43'>File<\/span><span style='color:#800080'>;<\/span><br \/><span style='color:#800000;font-weight:bold'>import<\/span><span style='color:#004a43'> java<\/span><span style='color:#808030'>.<\/span><span style='color:#004a43'>io<\/span><span style='color:#808030'>.<\/span><span style='color:#004a43'>FileReader<\/span><span style='color:#800080'>;<\/span><br \/><span style='color:#800000;font-weight:bold'>import<\/span><span style='color:#004a43'> java<\/span><span style='color:#808030'>.<\/span><span style='color:#004a43'>io<\/span><span style='color:#808030'>.<\/span><span style='color:#004a43'>FileWriter<\/span><span style='color:#800080'>;<\/span><br \/><span style='color:#800000;font-weight:bold'>import<\/span><span style='color:#004a43'> java<\/span><span style='color:#808030'>.<\/span><span style='color:#004a43'>io<\/span><span style='color:#808030'>.<\/span><span style='color:#004a43'>IOException<\/span><span style='color:#800080'>;<\/span><br \/><span style='color:#800000;font-weight:bold'>import<\/span><span style='color:#004a43'> java<\/span><span style='color:#808030'>.<\/span><span style='color:#004a43'>util<\/span><span style='color:#808030'>.<\/span><span style='color:#004a43'>Scanner<\/span><span style='color:#800080'>;<\/span><br \/><span style='color:#800000;font-weight:bold'>import<\/span><span style='color:#004a43'> java<\/span><span style='color:#808030'>.<\/span><span style='color:#004a43'>util<\/span><span style='color:#808030'>.<\/span><span style='color:#004a43'>regex<\/span><span style='color:#808030'>.<\/span><span style='color:#004a43'>Pattern<\/span><span style='color:#800080'>;<\/span><br \/><br \/><span style='color:#800000;font-weight:bold'>public<\/span> <span style='color:#800000;font-weight:bold'>class<\/span> Fixer <span style='color:#800080'>{<\/span><br \/>    <span style='color:#800000;font-weight:bold'>static<\/span> <span style='color:#bb7977;font-weight:bold'>File<\/span> infile <span style='color:#808030'>=<\/span> <span style='color:#800000;font-weight:bold'>new<\/span> <span style='color:#bb7977;font-weight:bold'>File<\/span><span style='color:#808030'>(<\/span><span style='color:#0000e6'>\"test.txt\"<\/span><span style='color:#808030'>)<\/span><span style='color:#800080'>;<\/span><br \/>    <span style='color:#800000;font-weight:bold'>static<\/span> <span style='color:#bb7977;font-weight:bold'>String<\/span><span style='color:#808030'>[<\/span><span style='color:#808030'>]<\/span> patternStrings <span style='color:#808030'>=<\/span> <span style='color:#800080'>{<\/span><span style='color:#0000e6'>\"ZAR\"<\/span><span style='color:#808030'>,<\/span> <span style='color:#0000e6'>\"&lt;TD([^&gt;]*)&gt;([0-9]{4})([0-9]{2})([0-9]{2})\"<\/span><span style='color:#800080'>}<\/span><span style='color:#800080'>;<\/span><br \/>    <span style='color:#800000;font-weight:bold'>static<\/span> <span style='color:#bb7977;font-weight:bold'>String<\/span><span style='color:#808030'>[<\/span><span style='color:#808030'>]<\/span> replacementStrings <span style='color:#808030'>=<\/span> <span style='color:#800080'>{<\/span><span style='color:#0000e6'>\"USD\"<\/span><span style='color:#808030'>,<\/span> <span style='color:#0000e6'>\"&lt;TD$1&gt;$2$4$3\"<\/span><span style='color:#800080'>}<\/span><span style='color:#800080'>;<\/span><br \/><br \/>    <span style='color:#800000;font-weight:bold'>public<\/span> <span style='color:#800000;font-weight:bold'>static<\/span> <span style='color:#bb7977'>void<\/span> main<span style='color:#808030'>(<\/span><span style='color:#bb7977;font-weight:bold'>String<\/span><span style='color:#808030'>[<\/span><span style='color:#808030'>]<\/span> args<span style='color:#808030'>)<\/span> <span style='color:#800000;font-weight:bold'>throws<\/span> <span style='color:#bb7977;font-weight:bold'>IOException<\/span> <span style='color:#800080'>{<\/span><br \/>        Pattern<span style='color:#808030'>[<\/span><span style='color:#808030'>]<\/span> patterns <span style='color:#808030'>=<\/span> <span style='color:#800000;font-weight:bold'>new<\/span> Pattern<span style='color:#808030'>[<\/span>patternStrings<span style='color:#808030'>.<\/span>length<span style='color:#808030'>]<\/span><span style='color:#800080'>;<\/span><br \/>        Scanner in <span style='color:#808030'>=<\/span> <span style='color:#800000;font-weight:bold'>new<\/span> Scanner<span style='color:#808030'>(<\/span><span style='color:#800000;font-weight:bold'>new<\/span> <span style='color:#bb7977;font-weight:bold'>FileReader<\/span><span style='color:#808030'>(<\/span>infile<span style='color:#808030'>)<\/span><span style='color:#808030'>)<\/span><span style='color:#800080'>;<\/span><br \/>        <br \/>        <span style='color:#696969'>\/\/ Compile patterns<\/span><br \/>        <span style='color:#800000;font-weight:bold'>for<\/span> <span style='color:#808030'>(<\/span><span style='color:#bb7977'>int<\/span> i<span style='color:#808030'>=<\/span><span style='color:#008c00'>0<\/span><span style='color:#800080'>;<\/span> i<span style='color:#808030'>&lt;<\/span>patternStrings<span style='color:#808030'>.<\/span>length<span style='color:#800080'>;<\/span> i<span style='color:#808030'>+<\/span><span style='color:#808030'>+<\/span><span style='color:#808030'>)<\/span> <span style='color:#800080'>{<\/span><br \/>            patterns<span style='color:#808030'>[<\/span>i<span style='color:#808030'>]<\/span> <span style='color:#808030'>=<\/span> Pattern<span style='color:#808030'>.<\/span>compile<span style='color:#808030'>(<\/span>patternStrings<span style='color:#808030'>[<\/span>i<span style='color:#808030'>]<\/span><span style='color:#808030'>)<\/span><span style='color:#800080'>;<\/span><br \/>        <span style='color:#800080'>}<\/span><br \/>        <br \/>        <span style='color:#696969'>\/\/ Create temporary file to hold outputs<\/span><br \/>        <span style='color:#bb7977;font-weight:bold'>File<\/span> tempfile <span style='color:#808030'>=<\/span> <span style='color:#bb7977;font-weight:bold'>File<\/span><span style='color:#808030'>.<\/span>createTempFile<span style='color:#808030'>(<\/span><span style='color:#0000e6'>\"tmp\"<\/span><span style='color:#808030'>,<\/span> <span style='color:#0000e6'>\"tmp\"<\/span><span style='color:#808030'>)<\/span><span style='color:#800080'>;<\/span><br \/><br \/>        <span style='color:#696969'>\/\/ Process file<\/span><br \/>        <span style='color:#bb7977;font-weight:bold'>FileWriter<\/span> outfile <span style='color:#808030'>=<\/span> <span style='color:#800000;font-weight:bold'>new<\/span> <span style='color:#bb7977;font-weight:bold'>FileWriter<\/span><span style='color:#808030'>(<\/span>tempfile<span style='color:#808030'>)<\/span><span style='color:#800080'>;<\/span><br \/>        <span style='color:#800000;font-weight:bold'>while<\/span> <span style='color:#808030'>(<\/span>in<span style='color:#808030'>.<\/span>hasNextLine<span style='color:#808030'>(<\/span><span style='color:#808030'>)<\/span><span style='color:#808030'>)<\/span> <span style='color:#800080'>{<\/span><br \/>            <span style='color:#bb7977;font-weight:bold'>String<\/span> line <span style='color:#808030'>=<\/span> in<span style='color:#808030'>.<\/span>nextLine<span style='color:#808030'>(<\/span><span style='color:#808030'>)<\/span><span style='color:#800080'>;<\/span><br \/>            <span style='color:#800000;font-weight:bold'>for<\/span> <span style='color:#808030'>(<\/span><span style='color:#bb7977'>int<\/span> i<span style='color:#808030'>=<\/span><span style='color:#008c00'>0<\/span><span style='color:#800080'>;<\/span> i <span style='color:#808030'>&lt;<\/span> patterns<span style='color:#808030'>.<\/span>length<span style='color:#800080'>;<\/span> i<span style='color:#808030'>+<\/span><span style='color:#808030'>+<\/span><span style='color:#808030'>)<\/span><br \/>                line <span style='color:#808030'>=<\/span> patterns<span style='color:#808030'>[<\/span>i<span style='color:#808030'>]<\/span><span style='color:#808030'>.<\/span>matcher<span style='color:#808030'>(<\/span>line<span style='color:#808030'>)<\/span><span style='color:#808030'>.<\/span>replaceAll<span style='color:#808030'>(<\/span>replacementStrings<span style='color:#808030'>[<\/span>i<span style='color:#808030'>]<\/span><span style='color:#808030'>)<\/span><span style='color:#800080'>;<\/span><br \/>            <br \/>            outfile<span style='color:#808030'>.<\/span>write<span style='color:#808030'>(<\/span>line <span style='color:#808030'>+<\/span> <span style='color:#bb7977;font-weight:bold'>System<\/span><span style='color:#808030'>.<\/span>getProperty<span style='color:#808030'>(<\/span><span style='color:#0000e6'>\"line.separator\"<\/span><span style='color:#808030'>)<\/span><span style='color:#808030'>)<\/span><span style='color:#800080'>;<\/span><br \/>        <span style='color:#800080'>}<\/span>        <br \/>        outfile<span style='color:#808030'>.<\/span>close<span style='color:#808030'>(<\/span><span style='color:#808030'>)<\/span><span style='color:#800080'>;<\/span><br \/>        <br \/>        <span style='color:#696969'>\/\/ move temp file back to filename<\/span><br \/>        tempfile<span style='color:#808030'>.<\/span>renameTo<span style='color:#808030'>(<\/span>infile<span style='color:#808030'>)<\/span><span style='color:#800080'>;<\/span><br \/>    <span style='color:#800080'>}<\/span><br \/><span style='color:#800080'>}<\/span><br \/><\/pre>\n<\/div>\n<div>Now, at this point someone is bound to say &#8220;but wait, people don&#8217;t write desktop apps in sed!&#8221;.  But that&#8217;s quite the point &#8211; Java was designed with programming in the large in mind, but it is really tedious for short programs.  In many cases, learning a small domain specific language and using it to solve your small problem is faster than learning how to do the same thing in your &#8220;one language&#8221;.<\/div>\n<div><\/div>\n<div>I wish I had more time to put examples together, but this situation just presented itself and got me thinking.<\/div>\n","protected":false},"excerpt":{"rendered":"<p>I carry a Leatherman on my belt every day wherever I go. It has become a bit of an extension of my body, which I only really notice when I have to fly somewhere and I&#8217;m forced to take it off for the flight. Then I get to my destination and I can&#8217;t open the [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_feature_clip_id":0,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_post_was_ever_published":false},"categories":[3],"tags":[187],"class_list":["post-62","post","type-post","status-publish","format-standard","hentry","category-programming","tag-ramble"],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/sandrock.co.za\/carl\/wp-json\/wp\/v2\/posts\/62","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/sandrock.co.za\/carl\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/sandrock.co.za\/carl\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/sandrock.co.za\/carl\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/sandrock.co.za\/carl\/wp-json\/wp\/v2\/comments?post=62"}],"version-history":[{"count":0,"href":"https:\/\/sandrock.co.za\/carl\/wp-json\/wp\/v2\/posts\/62\/revisions"}],"wp:attachment":[{"href":"https:\/\/sandrock.co.za\/carl\/wp-json\/wp\/v2\/media?parent=62"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/sandrock.co.za\/carl\/wp-json\/wp\/v2\/categories?post=62"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/sandrock.co.za\/carl\/wp-json\/wp\/v2\/tags?post=62"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}