<?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-1724548057125197090</id><updated>2011-04-21T22:09:07.514-07:00</updated><category term='C#'/><category term='Haskell'/><category term='Python'/><category term='Plone'/><category term='XPCOM'/><category term='Rebol'/><category term='CSS'/><category term='Ruby'/><category term='Javascript'/><category term='functional programming'/><category term='government'/><category term='Emacs'/><category term='open source'/><category term='IronPython'/><category term='Lisp'/><category term='Prolog'/><category term='blog'/><category term='Scheme'/><category term='OSS'/><category term='Erlang'/><title type='text'>Wheel of Ezekiel</title><subtitle type='html'></subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://kunosure.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1724548057125197090/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://kunosure.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Cynos</name><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>25</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-1724548057125197090.post-7454038946121836347</id><published>2007-11-15T14:47:00.000-08:00</published><updated>2007-11-15T16:48:33.316-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Javascript'/><title type='text'>Javascript scoping problems? Is it Firefox, IE or... Prototype?</title><content type='html'>I was asked to assist a friend who was experiencing some unusual behaviour in his web application. While it worked as expected in Internet Explorer, it was failing in Firefox, so he asked me to have a look.&lt;br /&gt;&lt;br /&gt;The relevant source code:&lt;br /&gt;&lt;br /&gt;&lt;pre  style="font-size:small;"&gt;&lt;tt&gt;&lt;b&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;lt;html&lt;/span&gt;&lt;/b&gt; &lt;span style="color: rgb(0, 153, 0);"&gt;xmlns&lt;/span&gt;&lt;span style="color: rgb(153, 0, 0);"&gt;=&lt;/span&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;"http://www.w3.org/1999/xhtml"&lt;/span&gt; &lt;span style="color: rgb(0, 153, 0);"&gt;xml:lang&lt;/span&gt;&lt;span style="color: rgb(153, 0, 0);"&gt;=&lt;/span&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;"en"&lt;/span&gt; &lt;span style="color: rgb(0, 153, 0);"&gt;lang&lt;/span&gt;&lt;span style="color: rgb(153, 0, 0);"&gt;=&lt;/span&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;"en"&lt;/span&gt;&lt;b&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;b&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;b&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;lt;script&lt;/span&gt;&lt;/b&gt; &lt;span style="color: rgb(0, 153, 0);"&gt;src&lt;/span&gt;&lt;span style="color: rgb(153, 0, 0);"&gt;=&lt;/span&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;"inc/third_party/prototype/prototype.js"&lt;/span&gt; &lt;span style="color: rgb(0, 153, 0);"&gt;type&lt;/span&gt;&lt;span style="color: rgb(153, 0, 0);"&gt;=&lt;/span&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;"text/javascript"&lt;/span&gt;&lt;b&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;b&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;lt;script&lt;/span&gt;&lt;/b&gt; &lt;span style="color: rgb(0, 153, 0);"&gt;src&lt;/span&gt;&lt;span style="color: rgb(153, 0, 0);"&gt;=&lt;/span&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;"inc/third_party/tooltip.js"&lt;/span&gt; &lt;span style="color: rgb(0, 153, 0);"&gt;type&lt;/span&gt;&lt;span style="color: rgb(153, 0, 0);"&gt;=&lt;/span&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;"text/javascript"&lt;/span&gt;&lt;b&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;b&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;lt;script&lt;/span&gt;&lt;/b&gt; &lt;span style="color: rgb(0, 153, 0);"&gt;src&lt;/span&gt;&lt;span style="color: rgb(153, 0, 0);"&gt;=&lt;/span&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;"inc/third_party/protoload.js"&lt;/span&gt; &lt;span style="color: rgb(0, 153, 0);"&gt;type&lt;/span&gt;&lt;span style="color: rgb(153, 0, 0);"&gt;=&lt;/span&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;"text/javascript"&lt;/span&gt;&lt;b&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;b&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;b&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;lt;div&lt;/span&gt;&lt;/b&gt; &lt;span style="color: rgb(0, 153, 0);"&gt;id&lt;/span&gt;&lt;span style="color: rgb(153, 0, 0);"&gt;=&lt;/span&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;"main"&lt;/span&gt;&lt;b&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;b&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;lt;script&lt;/span&gt;&lt;/b&gt; &lt;span style="color: rgb(0, 153, 0);"&gt;type&lt;/span&gt;&lt;span style="color: rgb(153, 0, 0);"&gt;=&lt;/span&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;"text/javascript"&lt;/span&gt;&lt;b&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;b&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;function&lt;/span&gt;&lt;/b&gt; &lt;b&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;update&lt;/span&gt;&lt;/b&gt;&lt;span style="color: rgb(153, 0, 0);"&gt;(&lt;/span&gt;orderby&lt;span style="color: rgb(153, 0, 0);"&gt;,&lt;/span&gt;sort&lt;span style="color: rgb(153, 0, 0);"&gt;,&lt;/span&gt;page&lt;span style="color: rgb(153, 0, 0);"&gt;)&lt;/span&gt; &lt;span style="color: rgb(255, 0, 0);"&gt;{&lt;/span&gt;&lt;br /&gt;  $&lt;span style="color: rgb(153, 0, 0);"&gt;(&lt;/span&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;"80"&lt;/span&gt;&lt;span style="color: rgb(153, 0, 0);"&gt;).&lt;/span&gt;&lt;b&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;update&lt;/span&gt;&lt;/b&gt;&lt;span style="color: rgb(153, 0, 0);"&gt;(&lt;/span&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;"&amp;lt;center&amp;gt;&amp;lt;img src=&lt;/span&gt;&lt;span style="color: rgb(204, 51, 204);"&gt;\"&lt;/span&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;images/loading/waiting.gif&lt;/span&gt;&lt;span style="color: rgb(204, 51, 204);"&gt;\"&lt;/span&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;/&amp;gt;&amp;lt;/center&amp;gt;"&lt;/span&gt;&lt;span style="color: rgb(153, 0, 0);"&gt;);&lt;/span&gt;&lt;br /&gt;  &lt;b&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;var&lt;/span&gt;&lt;/b&gt; request &lt;span style="color: rgb(153, 0, 0);"&gt;=&lt;/span&gt; &lt;span style="color: rgb(255, 0, 0);"&gt;"module/80.php?orderby="&lt;/span&gt;&lt;span style="color: rgb(153, 0, 0);"&gt;+&lt;/span&gt;orderby&lt;span style="color: rgb(153, 0, 0);"&gt;+&lt;/span&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;"&amp;amp;page="&lt;/span&gt;&lt;span style="color: rgb(153, 0, 0);"&gt;+&lt;/span&gt;page&lt;span style="color: rgb(153, 0, 0);"&gt;+&lt;/span&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;"&amp;amp;sort="&lt;/span&gt;&lt;span style="color: rgb(153, 0, 0);"&gt;+&lt;/span&gt;sort&lt;span style="color: rgb(153, 0, 0);"&gt;+&lt;/span&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;"&amp;amp;status_id=80"&lt;/span&gt;&lt;span style="color: rgb(153, 0, 0);"&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;b&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;new&lt;/span&gt;&lt;/b&gt; Ajax&lt;span style="color: rgb(153, 0, 0);"&gt;.&lt;/span&gt;&lt;b&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;Updater&lt;/span&gt;&lt;/b&gt;&lt;span style="color: rgb(153, 0, 0);"&gt;(&lt;/span&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;"80"&lt;/span&gt;&lt;span style="color: rgb(153, 0, 0);"&gt;,&lt;/span&gt; request&lt;span style="color: rgb(153, 0, 0);"&gt;,&lt;/span&gt; &lt;span style="color: rgb(255, 0, 0);"&gt;{&lt;/span&gt; method&lt;span style="color: rgb(153, 0, 0);"&gt;:&lt;/span&gt; &lt;span style="color: rgb(255, 0, 0);"&gt;"get"&lt;/span&gt; &lt;span style="color: rgb(255, 0, 0);"&gt;}&lt;/span&gt;&lt;span style="color: rgb(153, 0, 0);"&gt;);&lt;/span&gt;&lt;br /&gt;  &lt;span style="color: rgb(255, 0, 0);"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;b&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;new&lt;/span&gt;&lt;/b&gt; Ajax&lt;span style="color: rgb(153, 0, 0);"&gt;.&lt;/span&gt;&lt;b&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;Updater&lt;/span&gt;&lt;/b&gt;&lt;span style="color: rgb(153, 0, 0);"&gt;(&lt;/span&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;"80"&lt;/span&gt;&lt;span style="color: rgb(153, 0, 0);"&gt;,&lt;/span&gt; &lt;span style="color: rgb(255, 0, 0);"&gt;"module/80.php?status_id=80"&lt;/span&gt;&lt;span style="color: rgb(153, 0, 0);"&gt;,&lt;/span&gt; &lt;span style="color: rgb(255, 0, 0);"&gt;{&lt;/span&gt; method&lt;span style="color: rgb(153, 0, 0);"&gt;:&lt;/span&gt; &lt;span style="color: rgb(255, 0, 0);"&gt;"get"&lt;/span&gt; &lt;span style="color: rgb(255, 0, 0);"&gt;}&lt;/span&gt;&lt;span style="color: rgb(153, 0, 0);"&gt;);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;lt;div&lt;/span&gt;&lt;/b&gt; &lt;span style="color: rgb(0, 153, 0);"&gt;id&lt;/span&gt;&lt;span style="color: rgb(153, 0, 0);"&gt;=&lt;/span&gt;&lt;span style="color: rgb(0, 153, 0);"&gt;80&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 153, 0);"&gt;&amp;lt;img&lt;/span&gt; &lt;span style="color: rgb(0, 153, 0);"&gt;src&lt;/span&gt;&lt;span style="color: rgb(153, 0, 0);"&gt;=&lt;/span&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;"images/loading/waiting.gif"&lt;/span&gt;&lt;b&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;/&amp;gt;&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;b&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;b&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;b&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;b&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;/tt&gt;&lt;/pre&gt;&lt;br /&gt;The loading AJAX imported a table with headers like this:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_tMUFX8BcTDI/Rzzc4BGtQbI/AAAAAAAAAAk/o5ZBeIQuDJg/s1600-h/blownupheaders.PNG"&gt;&lt;img style="cursor: pointer;" src="http://4.bp.blogspot.com/_tMUFX8BcTDI/Rzzc4BGtQbI/AAAAAAAAAAk/o5ZBeIQuDJg/s400/blownupheaders.PNG" alt="" id="BLOGGER_PHOTO_ID_5133220530222875058" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Which rendered like this:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_tMUFX8BcTDI/RzzdLBGtQcI/AAAAAAAAAAs/6fdFUzeJesg/s1600-h/table.PNG"&gt;&lt;img style="cursor: pointer;" src="http://4.bp.blogspot.com/_tMUFX8BcTDI/RzzdLBGtQcI/AAAAAAAAAAs/6fdFUzeJesg/s400/table.PNG" alt="" id="BLOGGER_PHOTO_ID_5133220856640389570" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;The expected behaviour was that clicking the header would pull in an appropriately sorted table via an Ajax request, and it worked as expected in IE7.&lt;br /&gt;&lt;br /&gt;In Firefox however, clicking a header simply replaced the header with the &lt;span style="font-family: courier new;"&gt;orderby&lt;/span&gt;  value  being passed in the update() function:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_tMUFX8BcTDI/RzzdLBGtQdI/AAAAAAAAAA0/9zAu6F2s8SQ/s1600-h/firefoxheader.PNG"&gt;&lt;img style="cursor: pointer;" src="http://4.bp.blogspot.com/_tMUFX8BcTDI/RzzdLBGtQdI/AAAAAAAAAA0/9zAu6F2s8SQ/s400/firefoxheader.PNG" alt="" id="BLOGGER_PHOTO_ID_5133220856640389586" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Several minutes messing around with Firebug showed that it should work as written, although I could never get my breakpoints to fire off. (But as I haven't yet fully mastered Firebug, I put this down to my lack of experience)&lt;br /&gt;&lt;br /&gt;As I sat there stumped, a vague sense of déjà vu crept over me, and I suggested to my friend that he rename update() to something very unique.&lt;br /&gt;&lt;br /&gt;Which promptly resolved the issue. So, it was obviously a problem with namespace pollution... although I use the term 'namespace' liberally. Problem is, I can't replicate this using normal Javascript - that is, inline scripts will override external Javascript anytime.&lt;br /&gt;&lt;br /&gt;So, that leaves one option - Prototype is extending HTMLElement or similar with an update() method. After a bit of digging, &lt;a href="http://www.prototypejs.org/learn/extensions"&gt;my suspicions are confirmed&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;In browsers that support adding methods to prototype of native objects such as  &lt;code&gt;HTMLElement&lt;/code&gt; &lt;em&gt;all&lt;/em&gt; DOM extensions on the element are available by default without ever having to call &lt;code&gt;Element.extend()&lt;/code&gt;, dollar function or anything! ...Because the prototype of the native browser object is extended, all DOM elements have Prototype extension methods built-in. This, however, isn't true for IE which doesn't let anyone touch &lt;code&gt;HTMLElement.prototype&lt;/code&gt;.&lt;/blockquote&gt;That's one hell of a gotcha, and all to avoid using $()... I don't know if protecting HTMLElement.prototype is correct behaviour or not, but I'm now convinced that attaching your methods to it is very much incorrect.&lt;br /&gt;&lt;br /&gt;The Prototype documentation on this 'feature' states:&lt;br /&gt;&lt;blockquote&gt;This document reveals some clever hacks found in Prototype.&lt;/blockquote&gt;&lt;br /&gt;Clever? Very clever, yes. Hacks? Most definitely.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1724548057125197090-7454038946121836347?l=kunosure.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kunosure.blogspot.com/feeds/7454038946121836347/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1724548057125197090&amp;postID=7454038946121836347' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1724548057125197090/posts/default/7454038946121836347'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1724548057125197090/posts/default/7454038946121836347'/><link rel='alternate' type='text/html' href='http://kunosure.blogspot.com/2007/11/javascript-scoping-problems-is-it.html' title='Javascript scoping problems? Is it Firefox, IE or... Prototype?'/><author><name>Cynos</name><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/_tMUFX8BcTDI/Rzzc4BGtQbI/AAAAAAAAAAk/o5ZBeIQuDJg/s72-c/blownupheaders.PNG' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1724548057125197090.post-4574659829994560830</id><published>2007-06-04T19:56:00.000-07:00</published><updated>2007-06-06T21:04:05.499-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Haskell'/><title type='text'>An unscientific comparison 3.5 - getting the cookie, Haskell</title><content type='html'>&lt;span style="font-weight: bold; font-style: italic;"&gt;Part 3.5 of N in a series. Click &lt;/span&gt;&lt;a style="font-weight: bold; font-style: italic;" href="http://kunosure.blogspot.com/2007/06/unscientific-comparison-34-getting.html"&gt;here&lt;/a&gt;&lt;span style="font-weight: bold; font-style: italic;"&gt; for Part 3.4&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Wow. This was incredibly hard.&lt;br /&gt;&lt;style type="text/css"&gt;&lt;!--body.hl { background-color:#ffffff; }pre.hl { color:#000000; background-color:#ffffff; font-size:10pt; font-family:Courier New;border: 1px dashed #929292; padding-left: 5px; padding-top: 2px; padding-right: 5px; padding-bottom: 2px;}.hl.num { color:#2928ff; }.hl.esc { color:#ff00ff; }.hl.str { color:#FF0000; }.hl.dstr{ color:#818100; }.hl.slc { color:#838183; font-style:italic; }.hl.com { color:#838183; font-style:italic; }.hl.dir { color:#008200; }.hl.sym { color:#000000; font-weight:bold;}.hl.line { color:#555555; }.hl.kwa { color:#000099; font-weight:bold; }.hl.kwb { color:#770000; }.hl.kwc { color:#314F4F;}.hl.kwd { color:#000066;}//--&gt;&lt;/style&gt;&lt;br /&gt;Like, ludicrously hard. Nothing I've done before really prepared me for it. I thought I would be okay, I mean, pattern matching, no side effects? I loved that stuff in Erlang, bring it on! But then... then I met the typing system, and monads. Oh boy.&lt;br /&gt;&lt;br /&gt;Before I get to the code, I'd like to thank &lt;a href="http://porg.es/"&gt;Porges&lt;/a&gt; for his patient assistance with my struggling towards glimmers of comprehension. The file functions are his, as is the fact that my getCookie function works - he taught me a lot about monads in the process. :)&lt;br /&gt;&lt;br /&gt;&lt;pre class="hl"&gt;&lt;br /&gt;&lt;span class="hl line"&gt; 1 &lt;/span&gt;&lt;span class="hl kwa"&gt;module&lt;/span&gt; &lt;span class="hl kwc"&gt;FirstCookie&lt;/span&gt; &lt;span class="hl kwa"&gt;where&lt;/span&gt;&lt;br /&gt;&lt;span class="hl line"&gt; 2 &lt;/span&gt;&lt;br /&gt;&lt;span class="hl line"&gt; 3 &lt;/span&gt;&lt;span class="hl kwa"&gt;import&lt;/span&gt; &lt;span class="hl kwc"&gt;Network.HTTP&lt;/span&gt;&lt;br /&gt;&lt;span class="hl line"&gt; 4 &lt;/span&gt;&lt;span class="hl kwa"&gt;import&lt;/span&gt; &lt;span class="hl kwc"&gt;Network.Browser&lt;/span&gt;&lt;br /&gt;&lt;span class="hl line"&gt; 5 &lt;/span&gt;&lt;span class="hl kwa"&gt;import&lt;/span&gt; &lt;span class="hl kwc"&gt;Network.URI&lt;/span&gt;&lt;br /&gt;&lt;span class="hl line"&gt; 6 &lt;/span&gt;&lt;br /&gt;&lt;span class="hl line"&gt; 7 &lt;/span&gt;&lt;br /&gt;&lt;span class="hl line"&gt; 8 &lt;/span&gt;&lt;br /&gt;&lt;span class="hl line"&gt; 9 &lt;/span&gt;&lt;span class="hl kwd"&gt;getCookie&lt;/span&gt; user pwd uri ua &lt;span class="hl sym"&gt;=&lt;/span&gt; &lt;span class="hl kwa"&gt;do&lt;/span&gt;&lt;br /&gt;&lt;span class="hl line"&gt;10 &lt;/span&gt;                            redir &lt;span class="hl kwb"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="hl kwd"&gt;browse&lt;/span&gt; &lt;span class="hl kwb"&gt;$&lt;/span&gt; &lt;span class="hl kwd"&gt;getCookie'&lt;/span&gt; user pwd uri ua&lt;br /&gt;&lt;span class="hl line"&gt;11 &lt;/span&gt;                            &lt;span class="hl kwd"&gt;browse &lt;span class="hl kwb"&gt;$&lt;/span&gt; getCookie''&lt;/span&gt; redir&lt;br /&gt;&lt;span class="hl line"&gt;12 &lt;/span&gt;&lt;span class="hl str"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="hl line"&gt;13 &lt;/span&gt;&lt;span class="hl kwd"&gt;getCookie'&lt;/span&gt; user pwd uri ua &lt;span class="hl sym"&gt;=&lt;/span&gt; &lt;span class="hl kwa"&gt;do&lt;/span&gt;&lt;br /&gt;&lt;span class="hl line"&gt;14 &lt;/span&gt;  &lt;span class="hl kwd"&gt;setAllowRedirects&lt;/span&gt; &lt;span class="hl kwa"&gt;False&lt;/span&gt;&lt;br /&gt;&lt;span class="hl line"&gt;15 &lt;/span&gt;  &lt;span class="hl kwa"&gt;let&lt;/span&gt; &lt;span class="hl sym"&gt;(&lt;/span&gt;&lt;span class="hl kwc"&gt;Just&lt;/span&gt; parsed_uri&lt;span class="hl sym"&gt;) =&lt;/span&gt; &lt;span class="hl kwd"&gt;parseURI&lt;/span&gt; uri&lt;br /&gt;&lt;span class="hl line"&gt;16 &lt;/span&gt;  &lt;span class="hl kwa"&gt;let&lt;/span&gt; f &lt;span class="hl sym"&gt;=&lt;/span&gt; &lt;span class="hl kwd"&gt;Form&lt;/span&gt; &lt;span class="hl kwb"&gt;POST&lt;/span&gt; parsed_uri &lt;span class="hl sym"&gt;[(&lt;/span&gt;&lt;span class="hl str"&gt;"id"&lt;/span&gt;&lt;span class="hl sym"&gt;,&lt;/span&gt;user&lt;span class="hl sym"&gt;), (&lt;/span&gt;&lt;span class="hl str"&gt;"pwd"&lt;/span&gt;&lt;span class="hl sym"&gt;,&lt;/span&gt;pwd&lt;span class="hl sym"&gt;), (&lt;/span&gt;&lt;span class="hl str"&gt;"dologin"&lt;/span&gt;&lt;span class="hl sym"&gt;,&lt;/span&gt; &lt;span class="hl str"&gt;"yes"&lt;/span&gt;&lt;span class="hl sym"&gt;)]&lt;/span&gt;&lt;br /&gt;&lt;span class="hl line"&gt;17 &lt;/span&gt;  &lt;span class="hl sym"&gt;(&lt;/span&gt;uri&lt;span class="hl sym"&gt;,&lt;/span&gt;resp&lt;span class="hl kwb"&gt;) &amp;lt;-&lt;/span&gt; &lt;span class="hl kwd"&gt;request &lt;span class="hl kwb"&gt;$&lt;/span&gt; formToRequest&lt;/span&gt; f&lt;br /&gt;&lt;span class="hl line"&gt;18 &lt;/span&gt;  &lt;span class="hl kwa"&gt;let&lt;/span&gt; &lt;span class="hl sym"&gt;(&lt;/span&gt;&lt;span class="hl kwc"&gt;Just&lt;/span&gt; redirectLocation&lt;span class="hl sym"&gt;) =&lt;/span&gt; &lt;span class="hl kwd"&gt;findHeader&lt;/span&gt; &lt;span class="hl kwb"&gt;HdrLocation&lt;/span&gt; resp&lt;br /&gt;&lt;span class="hl line"&gt;19 &lt;/span&gt;  &lt;span class="hl kwa"&gt;let&lt;/span&gt; &lt;span class="hl sym"&gt;(&lt;/span&gt;&lt;span class="hl kwc"&gt;Just&lt;/span&gt; parsed_redir_uri&lt;span class="hl sym"&gt;) =&lt;/span&gt; &lt;span class="hl kwd"&gt;parseURI&lt;/span&gt; redirectLocation&lt;br /&gt;&lt;span class="hl line"&gt;20 &lt;/span&gt;  &lt;span class="hl kwd"&gt;return&lt;/span&gt; parsed_redir_uri&lt;br /&gt;&lt;span class="hl line"&gt;21 &lt;/span&gt;&lt;br /&gt;&lt;span class="hl line"&gt;22 &lt;/span&gt;&lt;span class="hl kwd"&gt;getCookie''&lt;/span&gt; uri &lt;span class="hl sym"&gt;=&lt;/span&gt; &lt;span class="hl kwa"&gt;do&lt;/span&gt;&lt;br /&gt;&lt;span class="hl line"&gt;23 &lt;/span&gt;                  &lt;span class="hl kwd"&gt;request &lt;span class="hl kwb"&gt;$&lt;/span&gt; defaultGETRequest&lt;/span&gt; uri&lt;br /&gt;&lt;span class="hl line"&gt;24 &lt;/span&gt;                  &lt;span class="hl kwd"&gt;getCookies&lt;/span&gt;&lt;br /&gt;&lt;span class="hl line"&gt;25 &lt;/span&gt;&lt;br /&gt;&lt;span class="hl line"&gt;26 &lt;/span&gt;&lt;br /&gt;&lt;span class="hl line"&gt;27 &lt;/span&gt;&lt;span class="hl slc"&gt;--readCookie takes a file path and returns&lt;/span&gt;&lt;br /&gt;&lt;span class="hl line"&gt;28 &lt;/span&gt;&lt;span class="hl slc"&gt;-- a Cookie read from that file.&lt;/span&gt;&lt;br /&gt;&lt;span class="hl line"&gt;29 &lt;/span&gt;&lt;span class="hl slc"&gt;--&lt;/span&gt;&lt;br /&gt;&lt;span class="hl line"&gt;30 &lt;/span&gt;&lt;span class="hl slc"&gt;--read converts something from string representation&lt;/span&gt;&lt;br /&gt;&lt;span class="hl line"&gt;31 &lt;/span&gt;readCookie &lt;span class="hl sym"&gt;::&lt;/span&gt; FilePath &lt;span class="hl sym"&gt;-&amp;gt;&lt;/span&gt; IO Cookie&lt;br /&gt;&lt;span class="hl line"&gt;32 &lt;/span&gt;&lt;span class="hl kwd"&gt;readCookie&lt;/span&gt; f &lt;span class="hl sym"&gt;=&lt;/span&gt; &lt;span class="hl kwa"&gt;do&lt;/span&gt;&lt;br /&gt;&lt;span class="hl line"&gt;33 &lt;/span&gt;  &lt;span class="hl slc"&gt;-- read in the contents of the file (&amp;lt;-: extract string from IO monad)&lt;/span&gt;&lt;br /&gt;&lt;span class="hl line"&gt;34 &lt;/span&gt;  contents &lt;span class="hl kwb"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="hl kwd"&gt;readFile&lt;/span&gt; f&lt;br /&gt;&lt;span class="hl line"&gt;35 &lt;/span&gt;  &lt;span class="hl slc"&gt;-- make a cookie from the contents&lt;/span&gt;&lt;br /&gt;&lt;span class="hl line"&gt;36 &lt;/span&gt;  &lt;span class="hl kwa"&gt;let&lt;/span&gt; cookie &lt;span class="hl sym"&gt;=&lt;/span&gt; &lt;span class="hl kwd"&gt;read&lt;/span&gt; contents&lt;br /&gt;&lt;span class="hl line"&gt;37 &lt;/span&gt;  &lt;span class="hl slc"&gt;-- return the cookie wrapped in the IO monad&lt;/span&gt;&lt;br /&gt;&lt;span class="hl line"&gt;38 &lt;/span&gt;  &lt;span class="hl kwd"&gt;return&lt;/span&gt; cookie&lt;br /&gt;&lt;span class="hl line"&gt;39 &lt;/span&gt;&lt;br /&gt;&lt;span class="hl line"&gt;40 &lt;/span&gt;&lt;span class="hl slc"&gt;--writeCookie takes a file path and a cookie and writes it&lt;/span&gt;&lt;br /&gt;&lt;span class="hl line"&gt;41 &lt;/span&gt;&lt;span class="hl slc"&gt;--&lt;/span&gt;&lt;br /&gt;&lt;span class="hl line"&gt;42 &lt;/span&gt;&lt;span class="hl slc"&gt;--show converts something to string representation&lt;/span&gt;&lt;br /&gt;&lt;span class="hl line"&gt;43 &lt;/span&gt;writeCookie &lt;span class="hl sym"&gt;::&lt;/span&gt; FilePath &lt;span class="hl sym"&gt;-&amp;gt;&lt;/span&gt; Cookie &lt;span class="hl sym"&gt;-&amp;gt;&lt;/span&gt; IO &lt;span class="hl sym"&gt;()&lt;/span&gt;&lt;br /&gt;&lt;span class="hl line"&gt;44 &lt;/span&gt;&lt;span class="hl kwd"&gt;writeCookie&lt;/span&gt; f c &lt;span class="hl sym"&gt;=&lt;/span&gt; &lt;span class="hl kwd"&gt;writeFile&lt;/span&gt; f &lt;span class="hl sym"&gt;(&lt;/span&gt;&lt;span class="hl kwd"&gt;show&lt;/span&gt; c&lt;span class="hl sym"&gt;)&lt;/span&gt;&lt;/pre&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;Comments&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;I found this unbelievably hard at first. Why? Two things, monads and typing.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Monads&lt;/span&gt;&lt;br /&gt;According to Wikipedia, a monad is a &lt;span style="font-style: italic;"&gt;"construction that, given an underlying &lt;/span&gt;&lt;span style="font-style: italic;"&gt;type system&lt;/span&gt;&lt;span style="font-style: italic;"&gt;, embeds a corresponding monadic type system into it"&lt;/span&gt;... which really explains it, no? There's a thousand metaphors to try and explain them.&lt;br /&gt;&lt;br /&gt;In the course of writing these functions, I had dealings with the following monads: Maybe, BrowserAction and IO. Here's my understanding of each (which could be entirely wrong).&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Maybe is a wrapper of sorts to allow polymorphic returns from functions that could fail, while retaining determinism. It seems well suited for chains of functions, where any function could fail and return Nothing. Maybe seems to remove the necessity for long manual chains of pattern matching and function calls. Maybe is also a bit like Schrodinger's Cat - until you look at it, you can't tell what the result was, hence 'extracting values' by using pattern matching to bind - that "&lt;span style="font-family:courier new;"&gt;(Just x)&lt;/span&gt;" stuff. Although I'm not sure quite what kind of entity Just is. Googling's not helping.&lt;/li&gt;&lt;/ul&gt;&lt;ul&gt;&lt;li&gt;BrowserAction holds state for the Browser module - from the &lt;a href="http://hackage.haskell.org/packages/archive/HTTP/3000.0.0/doc/html/Network-Browser.html"&gt;API documents&lt;/a&gt;, it looks like every stateful function returns an empty BrowserAction... not &lt;span style="font-style: italic;"&gt;quite&lt;/span&gt; sure how it works, but at least I know how and where the BrowserAction is coming from.&lt;/li&gt;&lt;/ul&gt;&lt;ul&gt;&lt;li&gt;IO is also stateful as far as I'm aware. I'm not sure how they achieve that, and would like to view the code they generate one day, like using macroexpand in Lisp, although I'm assured that it'll be a whole lot of ugly looking lambdas. But still, curiosity and all.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;The biggest problem with monads? My preconceptions about monads. I've been prepped to think that monads are confusing and complicated by reading about how confusing and complicated they are. When in reality, they're merely different. The term "monad" doesn't help, sounds quite daunting and theoretical. I'm trying to substitute the term "wuzzle" in my thinking about them, to make them sound cute and fuzzy... but Maybe wuzzle sounds kind of silly.&lt;br /&gt;&lt;br /&gt;But anyway, as is probably evident to any experienced Haskell hackers reading, I still have a very imperfect comprehension of how monads fit into the scheme of things, but they're not so scary now.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Typing&lt;/span&gt;&lt;br /&gt;Going hand in hand with my lack of understanding about monads was troubles with types. But they tie in together, after all, a monad is simply a construction that, given an underlying type system, embeds a corresponding monadic type system into it... but yes, realising a monad is a type was one of those minor epiphany moments. My main issue seems to be understanding the type notation used. I guess it's a case of practise makes perfect. I'm also unused to using a static typing system where I'm not casting all over the show, makes me feel uneasy.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Documentation&lt;/span&gt;&lt;br /&gt;I could've killed for some more indepth examples when I was writing this. I find API documents are great when you know what you're doing and just want to check you're passing the right arguments, but when you're trying to figure out how to do task X, API documents at best lend clues. A few examples and/or summary explaining the intended usage can be lifesavers.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Overall&lt;/span&gt;&lt;br /&gt;Haskell feels like it's adhering to a theory (category theory?) - this manifests in behaviour that may not be pragmatic, but it feels consistent with itself - the rules that govern Haskell, whatever they are, make themselves known in the "texture" of the language - I'm afraid I can't explain it better than that, it's more of an intuitive thing. I imagine that using Haskell would reveal the nature of this theory in a manner a mathematical layman like myself can grasp... but I also feel that a grasp of the theory would make using Haskell a lot easier.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1724548057125197090-4574659829994560830?l=kunosure.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kunosure.blogspot.com/feeds/4574659829994560830/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1724548057125197090&amp;postID=4574659829994560830' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1724548057125197090/posts/default/4574659829994560830'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1724548057125197090/posts/default/4574659829994560830'/><link rel='alternate' type='text/html' href='http://kunosure.blogspot.com/2007/06/unscientific-comparison-35-getting.html' title='An unscientific comparison 3.5 - getting the cookie, Haskell'/><author><name>Cynos</name><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>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1724548057125197090.post-2291226439403244829</id><published>2007-06-04T16:38:00.000-07:00</published><updated>2007-06-05T21:32:17.774-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><title type='text'>An unscientific comparison 3.4 - getting the cookie, Ruby</title><content type='html'>&lt;span style="font-style: italic; font-weight: bold;"&gt;Part 3.4 of N in a series. Click &lt;/span&gt;&lt;a style="font-style: italic; font-weight: bold;" href="http://kunosure.blogspot.com/2007/05/unscientific-comparison-332-getting.html"&gt;here&lt;/a&gt;&lt;span style="font-style: italic; font-weight: bold;"&gt; for Part 3.3.2&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Well, my first Ruby in a while, and it was certainly different to what I was expecting.  I finally figured out why people like certain aspects of it, but other aspects left me cold.&lt;br /&gt;&lt;br /&gt;But first, the code.&lt;br /&gt;&lt;style type="text/css"&gt;&lt;!--body.hl { background-color:#ffffff; }pre.hl { color:#000000; background-color:#ffffff; font-size:10pt; font-family:Courier New;border: 1px dashed #929292; padding-left: 5px; padding-top: 2px; padding-right: 5px; padding-bottom: 2px;}.hl.num { color:#2928ff; }.hl.esc { color:#ff00ff; }.hl.str { color:#FF0000; }.hl.dstr{ color:#818100; }.hl.slc { color:#838183; font-style:italic; }.hl.com { color:#838183; font-style:italic; }.hl.dir { color:#008200; }.hl.sym { color:#000000; font-weight:bold;}.hl.line { color:#555555; }.hl.kwa { color:#000099; font-weight:bold; }.hl.kwb { color:#770000; }.hl.kwc { color:#314F4F;}.hl.kwd { color:#000066;}//--&gt;&lt;/style&gt;&lt;br /&gt;&lt;pre class="hl"&gt;&lt;br /&gt;&lt;span class="hl line"&gt; 1 &lt;/span&gt;&lt;span class="hl kwa"&gt;require&lt;/span&gt; &lt;span class="hl str"&gt;'net/http'&lt;/span&gt;&lt;br /&gt;&lt;span class="hl line"&gt; 2 &lt;/span&gt;&lt;span class="hl kwa"&gt;require&lt;/span&gt; &lt;span class="hl str"&gt;'uri'&lt;/span&gt;&lt;br /&gt;&lt;span class="hl line"&gt; 3 &lt;/span&gt;&lt;br /&gt;&lt;span class="hl line"&gt; 4 &lt;/span&gt;&lt;br /&gt;&lt;span class="hl line"&gt; 5 &lt;/span&gt;&lt;span class="hl kwa"&gt;def&lt;/span&gt; &lt;span class="hl kwd"&gt;getCookie&lt;/span&gt;&lt;span class="hl sym"&gt;(&lt;/span&gt;user&lt;span class="hl sym"&gt;,&lt;/span&gt; pwd&lt;span class="hl sym"&gt;,&lt;/span&gt; uri&lt;span class="hl sym"&gt;,&lt;/span&gt; userAgent&lt;span class="hl sym"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class="hl line"&gt; 6 &lt;/span&gt; url &lt;span class="hl sym"&gt;=&lt;/span&gt;&lt;span class="hl kwc"&gt; URI&lt;/span&gt;&lt;span class="hl sym"&gt;.&lt;/span&gt;&lt;span class="hl kwd"&gt;parse&lt;/span&gt;&lt;span class="hl sym"&gt;(&lt;/span&gt;uri&lt;span class="hl sym"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class="hl line"&gt; 7 &lt;/span&gt; request &lt;span class="hl sym"&gt;=&lt;/span&gt; &lt;span class="hl kwc"&gt;Net&lt;span class="hl sym"&gt;::&lt;/span&gt;HTTP&lt;span class="hl sym"&gt;::&lt;/span&gt;&lt;/span&gt;Post&lt;span class="hl sym"&gt;.&lt;/span&gt;&lt;span class="hl kwd"&gt;new&lt;/span&gt;&lt;span class="hl sym"&gt;(&lt;/span&gt;url&lt;span class="hl sym"&gt;.&lt;/span&gt;path&lt;span class="hl sym"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class="hl line"&gt; 8 &lt;/span&gt;&lt;br /&gt;&lt;span class="hl line"&gt; 9 &lt;/span&gt; request&lt;span class="hl sym"&gt;.&lt;/span&gt;&lt;span class="hl kwd"&gt;set_form_data&lt;/span&gt;&lt;span class="hl sym"&gt;({&lt;/span&gt; &lt;span class="hl str"&gt;"id"&lt;/span&gt; &lt;span class="hl sym"&gt;=&amp;gt;&lt;/span&gt; user&lt;span class="hl sym"&gt;,&lt;/span&gt; &lt;span class="hl str"&gt;"pwd"&lt;/span&gt; &lt;span class="hl sym"&gt;=&amp;gt;&lt;/span&gt; pwd&lt;span class="hl sym"&gt;,&lt;/span&gt; &lt;span class="hl str"&gt;"dologin"&lt;/span&gt; &lt;span class="hl sym"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="hl str"&gt;"yes"&lt;/span&gt;&lt;span class="hl sym"&gt;})&lt;/span&gt;&lt;br /&gt;&lt;span class="hl line"&gt;10 &lt;/span&gt; request&lt;span class="hl sym"&gt;.&lt;/span&gt;&lt;span class="hl kwd"&gt;add_field&lt;/span&gt;&lt;span class="hl sym"&gt;(&lt;/span&gt;&lt;span class="hl str"&gt;"User-Agent"&lt;/span&gt;&lt;span class="hl sym"&gt;,&lt;/span&gt; userAgent&lt;span class="hl sym"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class="hl line"&gt;11 &lt;/span&gt;&lt;br /&gt;&lt;span class="hl line"&gt;12 &lt;/span&gt; response &lt;span class="hl sym"&gt;=&lt;/span&gt; &lt;span class="hl kwc"&gt;Net&lt;/span&gt;&lt;span class="hl sym"&gt;::&lt;/span&gt;HTTP&lt;span class="hl sym"&gt;.&lt;/span&gt;&lt;span class="hl kwd"&gt;new&lt;/span&gt;&lt;span class="hl sym"&gt;(&lt;/span&gt;url&lt;span class="hl sym"&gt;.&lt;/span&gt;host&lt;span class="hl sym"&gt;).&lt;/span&gt;&lt;span class="hl kwd"&gt;start&lt;/span&gt; &lt;span class="hl sym"&gt;{|&lt;/span&gt;http&lt;span class="hl sym"&gt;|&lt;/span&gt; http&lt;span class="hl sym"&gt;.&lt;/span&gt;&lt;span class="hl kwd"&gt;request&lt;/span&gt;&lt;span class="hl sym"&gt;(&lt;/span&gt;request&lt;span class="hl sym"&gt;) }&lt;/span&gt;&lt;br /&gt;&lt;span class="hl line"&gt;13 &lt;/span&gt; cookieUrl &lt;span class="hl sym"&gt;=&lt;/span&gt; &lt;span class="hl kwc"&gt;URI&lt;/span&gt;&lt;span class="hl sym"&gt;.&lt;/span&gt;&lt;span class="hl kwd"&gt;parse&lt;/span&gt;&lt;span class="hl sym"&gt;(&lt;/span&gt;response&lt;span class="hl sym"&gt;.&lt;/span&gt;&lt;span class="hl kwd"&gt;fetch&lt;/span&gt;&lt;span class="hl sym"&gt;(&lt;/span&gt;&lt;span class="hl str"&gt;"location"&lt;/span&gt;&lt;span class="hl sym"&gt;))&lt;/span&gt;&lt;br /&gt;&lt;span class="hl line"&gt;14 &lt;/span&gt;&lt;br /&gt;&lt;span class="hl line"&gt;15 &lt;/span&gt; cookieRequest &lt;span class="hl sym"&gt;=&lt;/span&gt; &lt;span class="hl kwc"&gt;Net&lt;/span&gt;&lt;span class="hl sym"&gt;::&lt;/span&gt;HTTP&lt;span class="hl sym"&gt;.&lt;/span&gt;&lt;span class="hl kwd"&gt;new&lt;/span&gt;&lt;span class="hl sym"&gt;(&lt;/span&gt;cookieUrl&lt;span class="hl sym"&gt;.&lt;/span&gt;host&lt;span class="hl sym"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class="hl line"&gt;16 &lt;/span&gt; cookieResponse &lt;span class="hl sym"&gt;=&lt;/span&gt; cookieRequest&lt;span class="hl sym"&gt;.&lt;/span&gt;&lt;span class="hl kwd"&gt;get&lt;/span&gt;&lt;span class="hl sym"&gt;(&lt;/span&gt;cookieUrl&lt;span class="hl sym"&gt;.&lt;/span&gt;path &lt;span class="hl sym"&gt;+&lt;/span&gt; &lt;span class="hl str"&gt;"?"&lt;/span&gt; &lt;span class="hl sym"&gt;+&lt;/span&gt; cookieUrl&lt;span class="hl sym"&gt;.&lt;/span&gt;query&lt;span class="hl sym"&gt;,&lt;br /&gt;                                     {&lt;/span&gt;&lt;span class="hl str"&gt;"User-Agent"&lt;/span&gt; &lt;span class="hl sym"&gt;=&amp;gt;&lt;/span&gt; userAgent&lt;span class="hl sym"&gt;})&lt;/span&gt;&lt;br /&gt;&lt;span class="hl line"&gt;17 &lt;/span&gt;&lt;br /&gt;&lt;span class="hl line"&gt;18 &lt;/span&gt; &lt;span class="hl kwa"&gt;return&lt;/span&gt; cookieResponse&lt;span class="hl sym"&gt;.&lt;/span&gt;&lt;span class="hl kwd"&gt;fetch&lt;/span&gt;&lt;span class="hl sym"&gt;(&lt;/span&gt;&lt;span class="hl str"&gt;"set-cookie"&lt;/span&gt;&lt;span class="hl sym"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class="hl line"&gt;19 &lt;/span&gt;&lt;span class="hl kwa"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;span class="hl line"&gt;20 &lt;/span&gt;&lt;br /&gt;&lt;span class="hl line"&gt;21 &lt;/span&gt;&lt;span class="hl kwa"&gt;def&lt;/span&gt; &lt;span class="hl kwd"&gt;storeCookie&lt;/span&gt;&lt;span class="hl sym"&gt;(&lt;/span&gt;cookie&lt;span class="hl sym"&gt;,&lt;/span&gt; filePath&lt;span class="hl sym"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class="hl line"&gt;22 &lt;/span&gt; File&lt;span class="hl sym"&gt;.&lt;/span&gt;&lt;span class="hl kwd"&gt;open&lt;/span&gt;&lt;span class="hl sym"&gt;(&lt;/span&gt;filePath&lt;span class="hl sym"&gt;,&lt;/span&gt; &lt;span class="hl str"&gt;"w"&lt;/span&gt;&lt;span class="hl sym"&gt;)&lt;/span&gt; &lt;span class="hl kwa"&gt;do&lt;/span&gt; &lt;span class="hl sym"&gt;|&lt;/span&gt;f&lt;span class="hl sym"&gt;|&lt;/span&gt;&lt;br /&gt;&lt;span class="hl line"&gt;23 &lt;/span&gt;  f&lt;span class="hl sym"&gt;.&lt;/span&gt;&lt;span class="hl kwd"&gt;puts&lt;/span&gt; cookie&lt;br /&gt;&lt;span class="hl line"&gt;24 &lt;/span&gt; &lt;span class="hl kwa"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;span class="hl line"&gt;25 &lt;/span&gt;&lt;span class="hl kwa"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;span class="hl line"&gt;26 &lt;/span&gt;&lt;br /&gt;&lt;span class="hl line"&gt;27 &lt;/span&gt;&lt;span class="hl kwa"&gt;def&lt;/span&gt; &lt;span class="hl kwd"&gt;retrieveCookie&lt;/span&gt;&lt;span class="hl sym"&gt;(&lt;/span&gt;filePath&lt;span class="hl sym"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class="hl line"&gt;28 &lt;/span&gt; f &lt;span class="hl sym"&gt;=&lt;/span&gt; File&lt;span class="hl sym"&gt;.&lt;/span&gt;&lt;span class="hl kwd"&gt;open&lt;/span&gt;&lt;span class="hl sym"&gt;(&lt;/span&gt;filePath&lt;span class="hl sym"&gt;,&lt;/span&gt; &lt;span class="hl str"&gt;"r"&lt;/span&gt;&lt;span class="hl sym"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class="hl line"&gt;29 &lt;/span&gt; cookie &lt;span class="hl sym"&gt;=&lt;/span&gt; f&lt;span class="hl sym"&gt;.&lt;/span&gt;&lt;span class="hl kwd"&gt;gets&lt;/span&gt;&lt;br /&gt;&lt;span class="hl line"&gt;30 &lt;/span&gt; f&lt;span class="hl sym"&gt;.&lt;/span&gt;&lt;span class="hl kwd"&gt;close&lt;/span&gt;&lt;br /&gt;&lt;span class="hl line"&gt;31 &lt;/span&gt; &lt;span class="hl kwa"&gt;return&lt;/span&gt; cookie&lt;br /&gt;&lt;span class="hl line"&gt;32 &lt;/span&gt;&lt;span class="hl kwa"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;Comments&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Documentation&lt;/span&gt;&lt;br /&gt;Maybe I'm looking in the wrong place, but Ruby documentation, to be frank, is terrible. The documentation that shipped with my Ruby install is out of date, and the online documentation is an API reference - but it's one of the most confusing API references I've ever used. For example, clicking on &lt;a href="http://www.ruby-doc.org/stdlib/libdoc/net/http/rdoc/classes/Net/HTTP/Post.html"&gt;Net::HTTP::Post&lt;/a&gt; under the classes list is not terribly illuminating.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;TMTOWDI&lt;/span&gt;&lt;br /&gt;I have nothing against multiple ways to perform the same task - except when it leads to multiple partially implemented ways to perform the same task. For example, POSTing.&lt;br /&gt;&lt;br /&gt;There is a method &lt;a href="http://www.ruby-doc.org/stdlib/libdoc/net/http/rdoc/classes/Net/HTTP.html#M001154"&gt;Net::HTTP.post&lt;/a&gt; which works almost identically to my usage  of the get method above. Would've shortened the code considerably. Except, if I can quote the docs:&lt;span style=";font-family:courier new;font-size:100%;"  &gt;&lt;br /&gt;&lt;/span&gt;&lt;blockquote style="font-family: courier new;"&gt;Posts data (must be a String) to path.&lt;br /&gt;&lt;/blockquote&gt;So, I can use the shorter and simpler method, but I need to convert the data into an urlencoded string myself before using it, or I can use the Request object which encodes the data for me, but has a more cumbersome method of dispatching that request.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;URI class&lt;/span&gt;&lt;br /&gt;It's normal to use a class to represent a URI, but is there a way to get my whole URI (including the query string I passed in originally) out? &lt;span style="font-family:courier new;"&gt;uri.path + "?" + uri.query&lt;/span&gt; feels a bit hackish.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Blocks&lt;/span&gt;&lt;br /&gt;Blocks are awesome. Python needs to steal these asap, single line lambdas don't count. One thing I gained from this was an appreciation for blocks and what they're good for. (Also, symbols. Yay for symbols, not that I used them here.)&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Overall&lt;/span&gt;&lt;br /&gt;I actually might try and find a third party improvement on this lot. The thought of using Net::HTTP again is a tad demotivational. Documentation is terrible - but I suspect that's because for most of Ruby's life, it's been used mainly by Japanese speaking people, so hasn't developed the mature English documentation yet. To any Ruby documentation writers reading: "More examples please." I'm a sucker for examples.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;a style="font-weight: bold;" href="http://kunosure.blogspot.com/2007/06/unscientific-comparison-35-getting.html"&gt;Click here for Part 3.5&lt;/a&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1724548057125197090-2291226439403244829?l=kunosure.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kunosure.blogspot.com/feeds/2291226439403244829/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1724548057125197090&amp;postID=2291226439403244829' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1724548057125197090/posts/default/2291226439403244829'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1724548057125197090/posts/default/2291226439403244829'/><link rel='alternate' type='text/html' href='http://kunosure.blogspot.com/2007/06/unscientific-comparison-34-getting.html' title='An unscientific comparison 3.4 - getting the cookie, Ruby'/><author><name>Cynos</name><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>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1724548057125197090.post-8300968948219160114</id><published>2007-05-25T20:57:00.000-07:00</published><updated>2007-06-05T21:30:02.242-07:00</updated><title type='text'>An unscientific comparison 3.3.2 - Getting the cookie, C# final</title><content type='html'>&lt;span style="font-weight: bold; font-style: italic;"&gt;Part 3.3.2 of N in a series - click &lt;/span&gt;&lt;a style="font-weight: bold; font-style: italic;" href="http://kunosure.blogspot.com/2007/05/unscientific-comparison-331-getting.html"&gt;here&lt;/a&gt;&lt;span style="font-weight: bold; font-style: italic;"&gt; for Part 3.3.1&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;So, final version. After my embarrassing myself with my &lt;a href="http://kunosure.blogspot.com/2007/05/c.html"&gt;initial approach&lt;/a&gt; and associated tantrum, I thought I better do it in a slightly saner fashion - don't want to have eaten &lt;a href="http://kunosure.blogspot.com/2007/05/unscientific-comparison-331-getting.html"&gt;humble pie&lt;/a&gt; for nothing.&lt;br /&gt;&lt;br /&gt;&lt;pre style="border: 1px dashed ;"&gt;&lt;br /&gt;&lt;div    style="background: white none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;font-family:Courier New;font-size:10pt;color:black;"&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;    1&lt;/span&gt; &lt;span style="color:blue;"&gt;using&lt;/span&gt; System;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;    2&lt;/span&gt; &lt;span style="color:blue;"&gt;using&lt;/span&gt; System.Collections.Generic;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;    3&lt;/span&gt; &lt;span style="color:blue;"&gt;using&lt;/span&gt; System.Collections.Specialized;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;    4&lt;/span&gt; &lt;span style="color:blue;"&gt;using&lt;/span&gt; System.Text;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;    5&lt;/span&gt; &lt;span style="color:blue;"&gt;using&lt;/span&gt; System.Net;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;    6&lt;/span&gt; &lt;span style="color:blue;"&gt;using&lt;/span&gt; System.IO;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;    7&lt;/span&gt; &lt;span style="color:blue;"&gt;using&lt;/span&gt; System.Runtime.Serialization;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;    8&lt;/span&gt; &lt;span style="color:blue;"&gt;using&lt;/span&gt; System.Runtime.Serialization.Formatters.Binary;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;    9&lt;/span&gt; &lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   10&lt;/span&gt; &lt;span style="color:blue;"&gt;namespace&lt;/span&gt; firstCookie3&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   11&lt;/span&gt; {&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   12&lt;/span&gt;     &lt;span style="color:blue;"&gt;class&lt;/span&gt; &lt;span style="color:teal;"&gt;CustomWebClient&lt;/span&gt; : &lt;span style="color:teal;"&gt;WebClient&lt;/span&gt;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   13&lt;/span&gt;     {&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   14&lt;/span&gt;         &lt;span style="color:blue;"&gt;public&lt;/span&gt; &lt;span style="color:blue;"&gt;event&lt;/span&gt; &lt;span style="color:teal;"&gt;Action&lt;/span&gt;&amp;lt;&lt;span style="color:teal;"&gt;WebRequest&lt;/span&gt;&amp;gt; ModifyRequest;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   15&lt;/span&gt; &lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   16&lt;/span&gt;         &lt;span style="color:blue;"&gt;public&lt;/span&gt; CustomWebClient() : &lt;span style="color:blue;"&gt;base&lt;/span&gt;() { }&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   17&lt;/span&gt; &lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   18&lt;/span&gt;         &lt;span style="color:blue;"&gt;protected&lt;/span&gt; &lt;span style="color:blue;"&gt;override&lt;/span&gt; &lt;span style="color:teal;"&gt;WebRequest&lt;/span&gt; GetWebRequest(&lt;span style="color:teal;"&gt;Uri&lt;/span&gt; address)&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   19&lt;/span&gt;         {&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   20&lt;/span&gt;             &lt;span style="color:teal;"&gt;WebRequest&lt;/span&gt; request = &lt;span style="color:blue;"&gt;base&lt;/span&gt;.GetWebRequest(address);&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   21&lt;/span&gt;             OnModifyRequest(request);&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   22&lt;/span&gt;             &lt;span style="color:blue;"&gt;return&lt;/span&gt; request;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   23&lt;/span&gt;         }&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   24&lt;/span&gt; &lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   25&lt;/span&gt;         &lt;span style="color:blue;"&gt;private&lt;/span&gt; &lt;span style="color:blue;"&gt;void&lt;/span&gt; OnModifyRequest(&lt;span style="color:teal;"&gt;WebRequest&lt;/span&gt; request)&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   26&lt;/span&gt;         {&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   27&lt;/span&gt;             &lt;span style="color:blue;"&gt;if&lt;/span&gt; (ModifyRequest != &lt;span style="color:blue;"&gt;null&lt;/span&gt;)&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   28&lt;/span&gt;                 ModifyRequest(request);&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   29&lt;/span&gt;         }&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   30&lt;/span&gt; &lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   31&lt;/span&gt;     }&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   32&lt;/span&gt; &lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   33&lt;/span&gt;     &lt;span style="color:blue;"&gt;class&lt;/span&gt; &lt;span style="color:teal;"&gt;CookieFunctions&lt;/span&gt;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   34&lt;/span&gt;     {&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   35&lt;/span&gt;         &lt;span style="color:blue;"&gt;public&lt;/span&gt; &lt;span style="color:blue;"&gt;static&lt;/span&gt; &lt;span style="color:teal;"&gt;CookieCollection&lt;/span&gt; GetCookie(&lt;span style="color:blue;"&gt;string&lt;/span&gt; user, &lt;span style="color:blue;"&gt;string&lt;/span&gt; pwd, &lt;span style="color:blue;"&gt;&lt;br /&gt;                                                   string&lt;/span&gt; uri, &lt;span style="color:blue;"&gt;string&lt;/span&gt; ua)&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   36&lt;/span&gt;         {&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   37&lt;/span&gt;             &lt;span style="color:teal;"&gt;NameValueCollection&lt;/span&gt; postData = &lt;span style="color:blue;"&gt;new&lt;/span&gt; &lt;span style="color:teal;"&gt;NameValueCollection&lt;/span&gt;();&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   38&lt;/span&gt;             &lt;span style="color:teal;"&gt;CookieContainer&lt;/span&gt; ckCont = &lt;span style="color:blue;"&gt;new&lt;/span&gt; &lt;span style="color:teal;"&gt;CookieContainer&lt;/span&gt;();&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   39&lt;/span&gt;             &lt;span style="color:teal;"&gt;CustomWebClient&lt;/span&gt; client = &lt;span style="color:blue;"&gt;new&lt;/span&gt; &lt;span style="color:teal;"&gt;CustomWebClient&lt;/span&gt;();&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   40&lt;/span&gt; &lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   41&lt;/span&gt;             postData[&lt;span style="color:maroon;"&gt;"id"&lt;/span&gt;] = user;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   42&lt;/span&gt;             postData[&lt;span style="color:maroon;"&gt;"pwd"&lt;/span&gt;] = pwd;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   43&lt;/span&gt;             postData[&lt;span style="color:maroon;"&gt;"dologin"&lt;/span&gt;] = &lt;span style="color:maroon;"&gt;"yes"&lt;/span&gt;;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   44&lt;/span&gt;             client.ModifyRequest += &lt;span style="color:blue;"&gt;delegate&lt;/span&gt;(&lt;span style="color:teal;"&gt;WebRequest&lt;/span&gt; req)&lt;br /&gt;                                 {&lt;br /&gt;                                 ((&lt;span style="color:teal;"&gt;HttpWebRequest&lt;/span&gt;)req).CookieContainer = ckCont;&lt;br /&gt;                                 };&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   45&lt;/span&gt;             client.ModifyRequest += &lt;span style="color:blue;"&gt;delegate&lt;/span&gt;(&lt;span style="color:teal;"&gt;WebRequest&lt;/span&gt; req)&lt;br /&gt;                                      {&lt;br /&gt;                                      ((&lt;span style="color:teal;"&gt;HttpWebRequest&lt;/span&gt;)req).UserAgent = ua;&lt;br /&gt;                                      };&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   46&lt;/span&gt;             client.UploadValues(uri, postData);&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   47&lt;/span&gt; &lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   48&lt;/span&gt;             &lt;span style="color:blue;"&gt;return&lt;/span&gt; ckCont.GetCookies(&lt;span style="color:blue;"&gt;new&lt;/span&gt; &lt;span style="color:teal;"&gt;Uri&lt;/span&gt;(uri));&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   49&lt;/span&gt;         }&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   50&lt;/span&gt; &lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   51&lt;/span&gt;         &lt;span style="color:blue;"&gt;public&lt;/span&gt; &lt;span style="color:blue;"&gt;static&lt;/span&gt; &lt;span style="color:blue;"&gt;void&lt;/span&gt; StoreCookie(&lt;span style="color:teal;"&gt;CookieCollection&lt;/span&gt; ck, &lt;span style="color:blue;"&gt;string&lt;/span&gt; filePath)&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   52&lt;/span&gt;         {&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   53&lt;/span&gt;             &lt;span style="color:teal;"&gt;IFormatter&lt;/span&gt; formatter = &lt;span style="color:blue;"&gt;new&lt;/span&gt; &lt;span style="color:teal;"&gt;BinaryFormatter&lt;/span&gt;();&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   54&lt;/span&gt;             &lt;span style="color:teal;"&gt;Stream&lt;/span&gt; outStream = &lt;span style="color:blue;"&gt;new&lt;/span&gt; &lt;span style="color:teal;"&gt;FileStream&lt;/span&gt;(filePath,&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   55&lt;/span&gt;                                               &lt;span style="color:teal;"&gt;FileMode&lt;/span&gt;.Create,&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   56&lt;/span&gt;                                               &lt;span style="color:teal;"&gt;FileAccess&lt;/span&gt;.Write,&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   57&lt;/span&gt;                                               &lt;span style="color:teal;"&gt;FileShare&lt;/span&gt;.None);&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   58&lt;/span&gt;             formatter.Serialize(outStream, ck);&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   59&lt;/span&gt;             outStream.Close();&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   60&lt;/span&gt;         }&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   61&lt;/span&gt; &lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   62&lt;/span&gt;         &lt;span style="color:blue;"&gt;public&lt;/span&gt; &lt;span style="color:blue;"&gt;static&lt;/span&gt; &lt;span style="color:teal;"&gt;CookieCollection&lt;/span&gt; RetrieveCookie(&lt;span style="color:blue;"&gt;string&lt;/span&gt; filePath)&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   63&lt;/span&gt;         {&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   64&lt;/span&gt;             &lt;span style="color:teal;"&gt;IFormatter&lt;/span&gt; formatter = &lt;span style="color:blue;"&gt;new&lt;/span&gt; &lt;span style="color:teal;"&gt;BinaryFormatter&lt;/span&gt;();&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   65&lt;/span&gt;             &lt;span style="color:teal;"&gt;Stream&lt;/span&gt; iStream = &lt;span style="color:blue;"&gt;new&lt;/span&gt; &lt;span style="color:teal;"&gt;FileStream&lt;/span&gt;(filePath,&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   66&lt;/span&gt;                                             &lt;span style="color:teal;"&gt;FileMode&lt;/span&gt;.Open,&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   67&lt;/span&gt;                                             &lt;span style="color:teal;"&gt;FileAccess&lt;/span&gt;.Read,&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   68&lt;/span&gt;                                             &lt;span style="color:teal;"&gt;FileShare&lt;/span&gt;.Read);&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   69&lt;/span&gt;             &lt;span style="color:teal;"&gt;CookieCollection&lt;/span&gt; ck = (&lt;span style="color:teal;"&gt;CookieCollection&lt;/span&gt;)formatter.Deserialize(iStream);&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   70&lt;/span&gt;             &lt;span style="color:blue;"&gt;return&lt;/span&gt; ck;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   71&lt;/span&gt;         }&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   72&lt;/span&gt; &lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   73&lt;/span&gt; &lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   74&lt;/span&gt;     }&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   75&lt;/span&gt; }&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;/pre&gt;The only comment I have to make is this - I'm glad they left that little hook there for me, but what worries me is the fact that I'm dependent on them doing so. I now understand what it's like to work in a &lt;a href="http://c2.com/cgi/wiki?BondageAndDisciplineLanguage"&gt;B&amp;D&lt;/a&gt; language.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;&lt;a href="http://kunosure.blogspot.com/2007/06/unscientific-comparison-34-getting.html"&gt;Click here for Part 3.4&lt;/a&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1724548057125197090-8300968948219160114?l=kunosure.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kunosure.blogspot.com/feeds/8300968948219160114/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1724548057125197090&amp;postID=8300968948219160114' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1724548057125197090/posts/default/8300968948219160114'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1724548057125197090/posts/default/8300968948219160114'/><link rel='alternate' type='text/html' href='http://kunosure.blogspot.com/2007/05/unscientific-comparison-332-getting.html' title='An unscientific comparison 3.3.2 - Getting the cookie, C# final'/><author><name>Cynos</name><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-1724548057125197090.post-7174389130877678942</id><published>2007-05-25T07:49:00.000-07:00</published><updated>2007-05-29T21:58:13.320-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><title type='text'>An unscientific comparison 3.3.1 - Getting the cookie, C# - a better way</title><content type='html'>&lt;span style="font-weight: bold; font-style: italic;"&gt;Part 3.3.1 of N in a series. Click &lt;/span&gt;&lt;a style="font-weight: bold; font-style: italic;" href="http://kunosure.blogspot.com/2007/05/c.html"&gt;here&lt;/a&gt;&lt;span style="font-weight: bold; font-style: italic;"&gt; for Part 3.3&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;Well, after much moaning and complaining and cursing of Bill Gates, I've decided that I need to update the C# attempt. Turns out, there's an easy way in .NET, and there's the horribly hard way.&lt;br /&gt;The easy way is to work with the library. The hard way is to to brute force it. Guess what my category my &lt;a href="http://kunosure.blogspot.com/2007/05/c.html"&gt;last attempt&lt;/a&gt; fell under.&lt;br /&gt;&lt;br /&gt;But let me start by saying that I probably would've left it at that if not for the patient guidance of these gentlemen - &lt;a href="http://www.handmethekeys.co.nz/"&gt;linkdown&lt;/a&gt;, &lt;a href="http://porg.es/blog/"&gt;porges&lt;/a&gt;, and a fellow by the nick of Kanibiss. So thanks guys.&lt;br /&gt;&lt;br /&gt;So,  a dissection of where I went wrong... well basically, it was the dismissal of &lt;a href="http://msdn2.microsoft.com/en-us/library/system.net.webclient.aspx"&gt;System.Net.WebClien&lt;/a&gt;t as being "too high level"... ah, hubris, my eternal enemy. Now I knew that to collect cookies I'd need to add a CookieContainer to an HttpWebRequest; my error was in assuming that WebClient didn't expose this in any way that I could use.&lt;br /&gt;&lt;br /&gt;WebClient contained all the functionality I had replicated in my HttpWebRequestWrapper - URI encoding, setting of headers, etc, butI just couldn't figure out how to set a CookieContainer and   without doing so, cookies aren't retained.&lt;br /&gt;&lt;br /&gt;I had actually seen the method &lt;a href="http://msdn2.microsoft.com/en-us/library/system.net.webclient.getwebrequest.aspx"&gt;WebClient.GetWebRequest&lt;/a&gt; in the documentation, but had dismissed it - after all, it only returned a WebRequest object, it didn't return a reference to the WebRequest object being used by WebClient. The documentation contained a code sample showing exactly what I needed to do, but my inexperience tripped me up here and I totally missed the import of it.&lt;br /&gt;&lt;br /&gt;After linkdown kept prompting me to investigate further, I downloaded &lt;a href="http://www.aisto.com/roeder/dotnet/"&gt;Reflector&lt;/a&gt; and had a closer look at WebClient. Specifically, the UploadValues method, as this was the one I would like to have used... and lo and behold, the way was revealed.&lt;br /&gt;&lt;pre style="border: 1px dashed ;"&gt;&lt;br /&gt;&lt;div    style="background: white none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;font-family:Courier New;font-size:10pt;color:black;"&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color:teal;"&gt;WebRequest&lt;/span&gt; request = &lt;span style="color:blue;"&gt;null&lt;/span&gt;;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color:blue;"&gt;this&lt;/span&gt;.ClearWebClientState();&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color:blue;"&gt;try&lt;/span&gt;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;{&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;    &lt;span style="color:blue;"&gt;byte&lt;/span&gt;[] buffer = &lt;span style="color:blue;"&gt;this&lt;/span&gt;.UploadValuesInternal(data);&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;    &lt;span style="color:blue;"&gt;this&lt;/span&gt;.m_Method = method;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;    request = &lt;span style="color:blue;"&gt;this&lt;/span&gt;.m_WebRequest = &lt;span style="color:blue;"&gt;this&lt;/span&gt;.GetWebRequest(&lt;span style="color:blue;"&gt;this&lt;/span&gt;.GetUri(address));&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;    &lt;span style="color:blue;"&gt;this&lt;/span&gt;.UploadBits(request, &lt;span style="color:blue;"&gt;null&lt;/span&gt;, buffer, &lt;span style="color:blue;"&gt;null&lt;/span&gt;, &lt;span style="color:blue;"&gt;null&lt;/span&gt;, &lt;span style="color:blue;"&gt;null&lt;/span&gt;, &lt;span style="color:blue;"&gt;null&lt;/span&gt;);&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;    &lt;span style="color:blue;"&gt;byte&lt;/span&gt;[] buffer2 = &lt;span style="color:blue;"&gt;this&lt;/span&gt;.DownloadBits(request, &lt;span style="color:blue;"&gt;null&lt;/span&gt;, &lt;span style="color:blue;"&gt;null&lt;/span&gt;, &lt;span style="color:blue;"&gt;null&lt;/span&gt;);&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;    &lt;span style="color:blue;"&gt;if&lt;/span&gt; (Logging.On)&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;    {&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;        Logging.Exit(Logging.Web, &lt;span style="color:blue;"&gt;this&lt;/span&gt;, &lt;span style="color:maroon;"&gt;"UploadValues"&lt;/span&gt;, address + &lt;span style="color:maroon;"&gt;", "&lt;/span&gt; + method);&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;    }&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;    buffer3 = buffer2;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;}&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;/pre&gt;The relevant bit is the call to... GetWebRequest. Ah. It was then that I noted that GetWebRequest was designated as virtual - that is, as overrideable by subclasses of WebClient.&lt;br /&gt;&lt;br /&gt;A minor epiphany occurred - the designers of this class had left me a hook, as it were, but I was too inexperienced to see it. I felt very stupid and elated at the same time.&lt;br /&gt;&lt;br /&gt;I quickly sat down and hacked out some code to use it, and then deleted it and rewrote it to allow for generalised usage - my first attempt looked like this -&lt;br /&gt;&lt;pre style="border: 1px dashed ;"&gt;&lt;br /&gt;&lt;div    style="background: white none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;font-family:Courier New;font-size:10pt;color:black;"&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;    1&lt;/span&gt; &lt;span style="color:blue;"&gt;using&lt;/span&gt; System;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;    2&lt;/span&gt; &lt;span style="color:blue;"&gt;using&lt;/span&gt; System.Collections.Generic;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;    3&lt;/span&gt; &lt;span style="color:blue;"&gt;using&lt;/span&gt; System.Text;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;    4&lt;/span&gt; &lt;span style="color:blue;"&gt;using&lt;/span&gt; System.Net;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;    5&lt;/span&gt; &lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;    6&lt;/span&gt; &lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;    7&lt;/span&gt; &lt;span style="color:blue;"&gt;namespace&lt;/span&gt; firstCookie2&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;    8&lt;/span&gt; {&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;    9&lt;/span&gt;     &lt;span style="color:blue;"&gt;public&lt;/span&gt; &lt;span style="color:blue;"&gt;delegate&lt;/span&gt; &lt;span style="color:blue;"&gt;void&lt;/span&gt; ModifyRequest(WebRequest w);&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   10&lt;/span&gt; &lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   11&lt;/span&gt; &lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   12&lt;/span&gt; &lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   13&lt;/span&gt; &lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   14&lt;/span&gt;     &lt;span style="color:blue;"&gt;class&lt;/span&gt; CustomWebClient : WebClient&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   15&lt;/span&gt;     {&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   16&lt;/span&gt;         Queue&amp;lt;modifyrequest&amp;gt; DelegateQueue;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   17&lt;/span&gt; &lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   18&lt;/span&gt;         &lt;span style="color:blue;"&gt;public&lt;/span&gt; CustomWebClient() : &lt;span style="color:blue;"&gt;base&lt;/span&gt;()&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   19&lt;/span&gt;         {&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   20&lt;/span&gt;             DelegateQueue&lt;modifyrequest&gt; = &lt;span style="color:blue;"&gt;new&lt;/span&gt; Queue&lt;modifyrequest&gt;();&lt;/modifyrequest&gt;&lt;/modifyrequest&gt;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   21&lt;/span&gt;         }&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   22&lt;/span&gt; &lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   23&lt;/span&gt;         &lt;span style="color:blue;"&gt;protected&lt;/span&gt; &lt;span style="color:blue;"&gt;override&lt;/span&gt; WebRequest GetWebRequest(Uri address)&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   24&lt;/span&gt;         {&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   25&lt;/span&gt;             WebRequest request = &lt;span style="color:blue;"&gt;base&lt;/span&gt;.GetWebRequest(address);&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   26&lt;/span&gt;             ApplyDelegates(request);&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   27&lt;/span&gt;             &lt;span style="color:blue;"&gt;return&lt;/span&gt; request;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   28&lt;/span&gt;         }&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   29&lt;/span&gt; &lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   30&lt;/span&gt;         &lt;span style="color:blue;"&gt;private&lt;/span&gt; WebRequest ApplyDelegates(WebRequest request)&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   31&lt;/span&gt;         {&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   32&lt;/span&gt;             &lt;span style="color:blue;"&gt;while&lt;/span&gt; (DelegateQueue.Count &gt; 0)&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   33&lt;/span&gt;             {&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   34&lt;/span&gt;                 ModifyRequest modDelegate = DelegateQueue.Dequeue();&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   35&lt;/span&gt;                 modDelegate(request);&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   36&lt;/span&gt;             }&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   37&lt;/span&gt;             &lt;span style="color:blue;"&gt;return&lt;/span&gt; request;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   38&lt;/span&gt;         }&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   39&lt;/span&gt;         &lt;span style="color:blue;"&gt;public&lt;/span&gt; &lt;span style="color:blue;"&gt;void&lt;/span&gt; AddDelegate(ModifyRequest del)&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   40&lt;/span&gt;         {&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   41&lt;/span&gt;             DelegateQueue.Enqueue(del);&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   42&lt;/span&gt;         }&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   43&lt;/span&gt; &lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   44&lt;/span&gt;     }&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   45&lt;/span&gt; }&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;After some sage advice from this &lt;a href="http://www.newtonsoft.com/Default.aspx"&gt;fine fellow&lt;/a&gt;, I modified the class to use events:&lt;br /&gt;&lt;br /&gt;&lt;pre style="border: 1px dashed ;"&gt;&lt;br /&gt;&lt;div    style="background: white none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;font-family:Courier New;font-size:10pt;color:black;"&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   26&lt;/span&gt; &lt;span style="color:blue;"&gt;class&lt;/span&gt; &lt;span style="color:teal;"&gt;CustomWebClient&lt;/span&gt; : &lt;span style="color:teal;"&gt;WebClient&lt;/span&gt;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   27&lt;/span&gt; {&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   28&lt;/span&gt;     &lt;span style="color:blue;"&gt;public&lt;/span&gt; &lt;span style="color:blue;"&gt;event&lt;/span&gt; &lt;span style="color:teal;"&gt;Action&lt;/span&gt;&lt;&lt;span style="color:teal;"&gt;WebRequest&lt;/span&gt;&gt; ModifyRequest;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   29&lt;/span&gt; &lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   30&lt;/span&gt;     &lt;span style="color:blue;"&gt;public&lt;/span&gt; CustomWebClient() : &lt;span style="color:blue;"&gt;base&lt;/span&gt;() { }&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   31&lt;/span&gt; &lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   32&lt;/span&gt;     &lt;span style="color:blue;"&gt;protected&lt;/span&gt; &lt;span style="color:blue;"&gt;override&lt;/span&gt; &lt;span style="color:teal;"&gt;WebRequest&lt;/span&gt; GetWebRequest(&lt;span style="color:teal;"&gt;Uri&lt;/span&gt; address)&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   33&lt;/span&gt;     {&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   34&lt;/span&gt;         &lt;span style="color:teal;"&gt;WebRequest&lt;/span&gt; request = &lt;span style="color:blue;"&gt;base&lt;/span&gt;.GetWebRequest(address);&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   35&lt;/span&gt;         OnModifyRequest(request);&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   36&lt;/span&gt;         &lt;span style="color:blue;"&gt;return&lt;/span&gt; request;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   37&lt;/span&gt;     }&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   38&lt;/span&gt; &lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   39&lt;/span&gt;     &lt;span style="color:blue;"&gt;private&lt;/span&gt; &lt;span style="color:blue;"&gt;void&lt;/span&gt; OnModifyRequest(&lt;span style="color:teal;"&gt;WebRequest&lt;/span&gt; request)&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   40&lt;/span&gt;     {&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   41&lt;/span&gt;         &lt;span style="color:blue;"&gt;if&lt;/span&gt; (ModifyRequest != &lt;span style="color:blue;"&gt;null&lt;/span&gt;)&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   42&lt;/span&gt;             ModifyRequest(request);&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   43&lt;/span&gt;     }&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   44&lt;/span&gt; &lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   45&lt;/span&gt; }&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Which can then be used like so:&lt;br /&gt;&lt;br /&gt;&lt;pre style="border: 1px dashed ;"&gt;&lt;br /&gt;&lt;div    style="background: white none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;font-family:Courier New;font-size:10pt;color:black;"&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color:blue;"&gt;static&lt;/span&gt; &lt;span style="color:blue;"&gt;void&lt;/span&gt; Main(&lt;span style="color:blue;"&gt;string&lt;/span&gt;[] args)&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;{&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;    &lt;span style="color:teal;"&gt;CustomWebClient&lt;/span&gt; w = &lt;span style="color:blue;"&gt;new&lt;/span&gt; &lt;span style="color:teal;"&gt;CustomWebClient&lt;/span&gt;();&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;    &lt;span style="color:teal;"&gt;CookieContainer&lt;/span&gt; cj = &lt;span style="color:blue;"&gt;new&lt;/span&gt; &lt;span style="color:teal;"&gt;CookieContainer&lt;/span&gt;();&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;    w.ModifyRequest += &lt;span style="color:blue;"&gt;delegate&lt;/span&gt;(&lt;span style="color:teal;"&gt;WebRequest&lt;/span&gt; request)&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;    {&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;        ((&lt;span style="color:teal;"&gt;HttpWebRequest&lt;/span&gt;)request).CookieContainer = cj;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;    };&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;    w.ModifyRequest += &lt;span style="color:blue;"&gt;delegate&lt;/span&gt;(&lt;span style="color:teal;"&gt;WebRequest&lt;/span&gt; request)&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;    {&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;        ((&lt;span style="color:teal;"&gt;HttpWebRequest&lt;/span&gt;)request).AllowAutoRedirect = &lt;span style="color:blue;"&gt;true&lt;/span&gt;;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;    };&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;    &lt;span style="color:blue;"&gt;string&lt;/span&gt; v = w.DownloadString(&lt;span style="color:maroon;"&gt;"http://www.google.co.nz"&lt;/span&gt;);&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;}&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;So. Now I get to rewrite the rest of my C# piece. I'm very embarrassed at my mistake, but I learnt a lot about .NET  in the process. I also have a far better vehicle for my HTTP requests now, far more flexible and far more powerful. My thanks to all who gave advice. :)&lt;br /&gt;&lt;br /&gt;&lt;a href="http://kunosure.blogspot.com/2007/05/unscientific-comparison-332-getting.html"&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;Click here for Part 3.3.2&lt;/span&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1724548057125197090-7174389130877678942?l=kunosure.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kunosure.blogspot.com/feeds/7174389130877678942/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1724548057125197090&amp;postID=7174389130877678942' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1724548057125197090/posts/default/7174389130877678942'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1724548057125197090/posts/default/7174389130877678942'/><link rel='alternate' type='text/html' href='http://kunosure.blogspot.com/2007/05/unscientific-comparison-331-getting.html' title='An unscientific comparison 3.3.1 - Getting the cookie, C# - a better way'/><author><name>Cynos</name><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-1724548057125197090.post-6705432038367026833</id><published>2007-05-20T05:58:00.000-07:00</published><updated>2007-05-29T22:01:40.130-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><title type='text'>An unscientific comparison 3.3 - Getting the cookie, C#</title><content type='html'>&lt;span style="font-weight: bold; font-style: italic;"&gt;Part 3.3 of N in a series. Click &lt;a href="http://kunosure.blogspot.com/2007/05/unscientific-comparison-32-getting.html"&gt;here&lt;/a&gt; for part 3.2.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Wow, this was unexpectedly unpleasant. After a few months of using C#, I'd grown quite fond of it and .NET - that fondness got a battering tonight.&lt;br /&gt;&lt;br /&gt;And all I wanted to do was subclass &lt;a href="http://msdn2.microsoft.com/en-us/library/system.net.httpwebrequest%28vs.80%29.aspx"&gt;System.Net.HttpWebRequest&lt;/a&gt;. But first, the code.&lt;br /&gt;&lt;br /&gt;&lt;div    style="border: 1px dashed ; background: white none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;font-family:Courier New;font-size:10pt;color:black;"&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;    1&lt;/span&gt; &lt;span style="color:blue;"&gt;using&lt;/span&gt; System;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;    2&lt;/span&gt; &lt;span style="color:blue;"&gt;using&lt;/span&gt; System.Collections.Generic;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;    3&lt;/span&gt; &lt;span style="color:blue;"&gt;using&lt;/span&gt; System.Text;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;    4&lt;/span&gt; &lt;span style="color:blue;"&gt;using&lt;/span&gt; System.Net;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;    5&lt;/span&gt; &lt;span style="color:blue;"&gt;using&lt;/span&gt; System.Web;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;    6&lt;/span&gt; &lt;span style="color:blue;"&gt;using&lt;/span&gt; System.IO;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;    7&lt;/span&gt; &lt;span style="color:blue;"&gt;using&lt;/span&gt; System.Runtime.Serialization;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;    8&lt;/span&gt; &lt;span style="color:blue;"&gt;using&lt;/span&gt; System.Runtime.Serialization.Formatters.Binary;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;    9&lt;/span&gt; &lt;span style="color:blue;"&gt;using&lt;/span&gt; &lt;span style="color:teal;"&gt;StringHashTable&lt;/span&gt; = System.Collections.Generic.&lt;span style="color:teal;"&gt;Dictionary&lt;/span&gt;&lt;&lt;span style="color:blue;"&gt;string&lt;/span&gt;, &lt;span style="color:blue;"&gt;string&lt;/span&gt;&gt;;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   10&lt;/span&gt; &lt;span style="color:blue;"&gt;using&lt;/span&gt; &lt;span style="color:teal;"&gt;StringList&lt;/span&gt; = System.Collections.Generic.&lt;span style="color:teal;"&gt;List&lt;/span&gt;&lt;&lt;span style="color:blue;"&gt;string&lt;/span&gt;&gt;;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   11&lt;/span&gt; &lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   12&lt;/span&gt; &lt;span style="color:blue;"&gt;namespace&lt;/span&gt; firstCookie&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   13&lt;/span&gt; {&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   14&lt;/span&gt;     &lt;span style="color:blue;"&gt;class&lt;/span&gt; &lt;span style="color:teal;"&gt;HttpRequestWrapper&lt;/span&gt;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   15&lt;/span&gt;     {&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   16&lt;/span&gt;         &lt;span style="color:teal;"&gt;HttpWebRequest&lt;/span&gt; request;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   17&lt;/span&gt;         &lt;span style="color:teal;"&gt;StringHashTable&lt;/span&gt; postData;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   18&lt;/span&gt; &lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   19&lt;/span&gt;         &lt;span style="color:blue;"&gt;public&lt;/span&gt; HttpRequestWrapper(&lt;span style="color:blue;"&gt;string&lt;/span&gt; uri)&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   20&lt;/span&gt;         {   &lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   21&lt;/span&gt;             request = (&lt;span style="color:teal;"&gt;HttpWebRequest&lt;/span&gt;)&lt;span style="color:teal;"&gt;WebRequest&lt;/span&gt;.Create(uri);&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   22&lt;/span&gt; &lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   23&lt;/span&gt;         }&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   24&lt;/span&gt; &lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   25&lt;/span&gt;         &lt;span style="color:blue;"&gt;public&lt;/span&gt; &lt;span style="color:teal;"&gt;HttpWebResponse&lt;/span&gt; Post()&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   26&lt;/span&gt;         {&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   27&lt;/span&gt;             &lt;span style="color:blue;"&gt;if&lt;/span&gt; (request.Method != &lt;span style="color:maroon;"&gt;"POST"&lt;/span&gt;) request.Method = &lt;span style="color:maroon;"&gt;"POST"&lt;/span&gt;;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   28&lt;/span&gt; &lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   29&lt;/span&gt;             &lt;span style="color:green;"&gt;/*Prepare data - If I haven't actually set the data,&lt;br /&gt;                  then I deserve an exception*/&lt;/span&gt;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   30&lt;/span&gt;             &lt;span style="color:blue;"&gt;byte&lt;/span&gt;[] preppedData = prepareData(postData);&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   31&lt;/span&gt;             request.ContentType = &lt;span style="color:maroon;"&gt;"application/x-www-form-urlencoded"&lt;/span&gt;;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   32&lt;/span&gt;             request.ContentLength = preppedData.Length;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   33&lt;/span&gt; &lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   34&lt;/span&gt;             &lt;span style="color:green;"&gt;//Now POST&lt;/span&gt;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   35&lt;/span&gt;             &lt;span style="color:teal;"&gt;Stream&lt;/span&gt; postStream = request.GetRequestStream();&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   36&lt;/span&gt;             postStream.Write(preppedData, 0, preppedData.Length);&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   37&lt;/span&gt;             &lt;span style="color:blue;"&gt;return&lt;/span&gt; (&lt;span style="color:teal;"&gt;HttpWebResponse&lt;/span&gt;)request.GetResponse();&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   38&lt;/span&gt;         }&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   39&lt;/span&gt; &lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   40&lt;/span&gt;         &lt;span style="color:blue;"&gt;private&lt;/span&gt; &lt;span style="color:blue;"&gt;byte&lt;/span&gt;[] prepareData(&lt;span style="color:teal;"&gt;StringHashTable&lt;/span&gt; postData)&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   41&lt;/span&gt;         {&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   42&lt;/span&gt;             &lt;span style="color:green;"&gt;//Firstly, convert data to usual query string form.&lt;/span&gt;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   43&lt;/span&gt;             &lt;span style="color:blue;"&gt;string&lt;/span&gt; formatString = &lt;span style="color:maroon;"&gt;"{0}={1}"&lt;/span&gt;;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   44&lt;/span&gt;             &lt;span style="color:teal;"&gt;StringList&lt;/span&gt; pairsList = &lt;span style="color:blue;"&gt;new&lt;/span&gt; &lt;span style="color:teal;"&gt;StringList&lt;/span&gt;();&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   45&lt;/span&gt;             &lt;span style="color:blue;"&gt;foreach&lt;/span&gt; (&lt;span style="color:blue;"&gt;string&lt;/span&gt; key &lt;span style="color:blue;"&gt;in&lt;/span&gt; postData.Keys)&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   46&lt;/span&gt;             {&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   47&lt;/span&gt;                 &lt;span style="color:blue;"&gt;string&lt;/span&gt; encodedKey = &lt;span style="color:teal;"&gt;HttpUtility&lt;/span&gt;.UrlEncode(key);&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   48&lt;/span&gt;                 &lt;span style="color:blue;"&gt;string&lt;/span&gt; encodedValue = &lt;span style="color:teal;"&gt;HttpUtility&lt;/span&gt;.UrlEncode(postData[key]);&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   49&lt;/span&gt;                 &lt;span style="color:blue;"&gt;string&lt;/span&gt; encodedString = &lt;span style="color:teal;"&gt;String&lt;/span&gt;.Format(formatString,&lt;br /&gt;                                                         encodedKey,&lt;br /&gt;                                                         encodedValue);&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   50&lt;/span&gt;                 pairsList.Add(encodedString);&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   51&lt;/span&gt;             }&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   52&lt;/span&gt;             &lt;span style="color:blue;"&gt;string&lt;/span&gt; queryString = &lt;span style="color:teal;"&gt;String&lt;/span&gt;.Join(&lt;span style="color:maroon;"&gt;"&amp;"&lt;/span&gt;, pairsList.ToArray());&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   53&lt;/span&gt; &lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   54&lt;/span&gt;             &lt;span style="color:green;"&gt;/*Now, convert string to byte[] - it's needed in this format,&lt;br /&gt;                  can't quite say why.*/&lt;/span&gt;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   55&lt;/span&gt;             &lt;span style="color:teal;"&gt;ASCIIEncoding&lt;/span&gt; byteEncoder = &lt;span style="color:blue;"&gt;new&lt;/span&gt; &lt;span style="color:teal;"&gt;ASCIIEncoding&lt;/span&gt;();&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   56&lt;/span&gt;             &lt;span style="color:blue;"&gt;byte&lt;/span&gt;[] encodedData = byteEncoder.GetBytes(queryString);&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   57&lt;/span&gt;             &lt;span style="color:blue;"&gt;return&lt;/span&gt; encodedData;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   58&lt;/span&gt;         }&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   59&lt;/span&gt; &lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   60&lt;/span&gt;         &lt;span style="color:blue;"&gt;public&lt;/span&gt; &lt;span style="color:teal;"&gt;StringHashTable&lt;/span&gt; formData&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   61&lt;/span&gt;         {&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   62&lt;/span&gt;             &lt;span style="color:green;"&gt;//Futureproof this, my Python side just wants to make postData public.&lt;/span&gt;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   63&lt;/span&gt;             &lt;span style="color:blue;"&gt;get&lt;/span&gt; { &lt;span style="color:blue;"&gt;return&lt;/span&gt; postData; }&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   64&lt;/span&gt;             &lt;span style="color:blue;"&gt;set&lt;/span&gt; { postData = &lt;span style="color:blue;"&gt;value&lt;/span&gt;; }&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   65&lt;/span&gt;         }&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   66&lt;/span&gt; &lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   67&lt;/span&gt;         &lt;span style="color:blue;"&gt;public&lt;/span&gt; &lt;span style="color:blue;"&gt;string&lt;/span&gt; Method&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   68&lt;/span&gt;         {&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   69&lt;/span&gt;             &lt;span style="color:blue;"&gt;get&lt;/span&gt; { &lt;span style="color:blue;"&gt;return&lt;/span&gt; request.Method; }&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   70&lt;/span&gt;             &lt;span style="color:blue;"&gt;set&lt;/span&gt; { request.Method = &lt;span style="color:blue;"&gt;value&lt;/span&gt;; }&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   71&lt;/span&gt;         }&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   72&lt;/span&gt; &lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   73&lt;/span&gt;         &lt;span style="color:blue;"&gt;public&lt;/span&gt; &lt;span style="color:blue;"&gt;string&lt;/span&gt; UserAgent&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   74&lt;/span&gt;         {&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   75&lt;/span&gt;             &lt;span style="color:blue;"&gt;get&lt;/span&gt; { &lt;span style="color:blue;"&gt;return&lt;/span&gt; request.UserAgent; }&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   76&lt;/span&gt;             &lt;span style="color:blue;"&gt;set&lt;/span&gt; { request.UserAgent = &lt;span style="color:blue;"&gt;value&lt;/span&gt;; }&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   77&lt;/span&gt;         }&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   78&lt;/span&gt; &lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   79&lt;/span&gt;         &lt;span style="color:blue;"&gt;public&lt;/span&gt; &lt;span style="color:teal;"&gt;CookieContainer&lt;/span&gt; CookieContainer&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   80&lt;/span&gt;         {&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   81&lt;/span&gt;             &lt;span style="color:blue;"&gt;get&lt;/span&gt; { &lt;span style="color:blue;"&gt;return&lt;/span&gt; request.CookieContainer; }&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   82&lt;/span&gt;             &lt;span style="color:blue;"&gt;set&lt;/span&gt; { request.CookieContainer = &lt;span style="color:blue;"&gt;value&lt;/span&gt;; }&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   83&lt;/span&gt;         }&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   84&lt;/span&gt; &lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   85&lt;/span&gt;         &lt;span style="color:blue;"&gt;public&lt;/span&gt; &lt;span style="color:blue;"&gt;bool&lt;/span&gt; AllowAutoRedirect&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   86&lt;/span&gt;         {&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   87&lt;/span&gt;             &lt;span style="color:blue;"&gt;get&lt;/span&gt; { &lt;span style="color:blue;"&gt;return&lt;/span&gt; request.AllowAutoRedirect; }&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   88&lt;/span&gt;             &lt;span style="color:blue;"&gt;set&lt;/span&gt; { request.AllowAutoRedirect = &lt;span style="color:blue;"&gt;value&lt;/span&gt;; }&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   89&lt;/span&gt;         }&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   90&lt;/span&gt; &lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   91&lt;/span&gt;     }&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   92&lt;/span&gt; &lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   93&lt;/span&gt;     &lt;span style="color:blue;"&gt;class&lt;/span&gt; &lt;span style="color:teal;"&gt;RequestFunctions&lt;/span&gt;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   94&lt;/span&gt;     {&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   95&lt;/span&gt;        &lt;span style="color:blue;"&gt;public&lt;/span&gt; &lt;span style="color:blue;"&gt;static&lt;/span&gt; &lt;span style="color:teal;"&gt;HttpRequestWrapper&lt;/span&gt; CreateRequest(&lt;span style="color:blue;"&gt;string&lt;/span&gt; uri, &lt;span style="color:blue;"&gt;string&lt;/span&gt; userAgent)&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   96&lt;/span&gt;         {&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   97&lt;/span&gt;             &lt;span style="color:teal;"&gt;HttpRequestWrapper&lt;/span&gt; req = &lt;span style="color:blue;"&gt;new&lt;/span&gt; &lt;span style="color:teal;"&gt;HttpRequestWrapper&lt;/span&gt;(uri);&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   98&lt;/span&gt;             req.UserAgent = userAgent;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   99&lt;/span&gt;             req.Method = &lt;span style="color:maroon;"&gt;"GET"&lt;/span&gt;;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;  100&lt;/span&gt;             &lt;span style="color:blue;"&gt;return&lt;/span&gt; req;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;  101&lt;/span&gt;         }&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;  102&lt;/span&gt; &lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;  103&lt;/span&gt;         &lt;span style="color:blue;"&gt;public&lt;/span&gt; &lt;span style="color:blue;"&gt;static&lt;/span&gt; &lt;span style="color:teal;"&gt;HttpRequestWrapper&lt;/span&gt; CreateRequest(&lt;span style="color:blue;"&gt;string&lt;/span&gt; uri,&lt;br /&gt;                                                           &lt;span style="color:teal;"&gt;StringHashTable&lt;/span&gt; data, &lt;span style="color:blue;"&gt;&lt;br /&gt;                                                           string&lt;/span&gt; userAgent)&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;  104&lt;/span&gt;         {&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;  105&lt;/span&gt; &lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;  106&lt;/span&gt;             &lt;span style="color:teal;"&gt;HttpRequestWrapper&lt;/span&gt; req = CreateRequest(uri, userAgent);&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;  107&lt;/span&gt;             req.Method = &lt;span style="color:maroon;"&gt;"POST"&lt;/span&gt;;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;  108&lt;/span&gt;             req.formData = data;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;  109&lt;/span&gt;             &lt;span style="color:blue;"&gt;return&lt;/span&gt; req;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;  110&lt;/span&gt;         }&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;  111&lt;/span&gt; &lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;  112&lt;/span&gt; &lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;  113&lt;/span&gt;     }&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;  114&lt;/span&gt; &lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;  115&lt;/span&gt; &lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;  116&lt;/span&gt; &lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;  117&lt;/span&gt;     &lt;span style="color:blue;"&gt;class&lt;/span&gt; &lt;span style="color:teal;"&gt;CookieFunctions&lt;/span&gt;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;  118&lt;/span&gt;     {&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;  119&lt;/span&gt;         &lt;span style="color:blue;"&gt;public&lt;/span&gt; &lt;span style="color:blue;"&gt;static&lt;/span&gt; &lt;span style="color:teal;"&gt;CookieCollection&lt;/span&gt; GetCookie(&lt;span style="color:blue;"&gt;string&lt;/span&gt; user, &lt;span style="color:blue;"&gt;&lt;br /&gt;                                                     string&lt;/span&gt; pwd, &lt;span style="color:blue;"&gt;&lt;br /&gt;                                                     string&lt;/span&gt; uri,&lt;br /&gt;                                                     &lt;span style="color:blue;"&gt;string&lt;/span&gt; ua)&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;  120&lt;/span&gt;         {&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;  121&lt;/span&gt;             &lt;span style="color:teal;"&gt;StringHashTable&lt;/span&gt; postData = &lt;span style="color:blue;"&gt;new&lt;/span&gt; &lt;span style="color:teal;"&gt;StringHashTable&lt;/span&gt;();&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;  122&lt;/span&gt;             postData[&lt;span style="color:maroon;"&gt;"id"&lt;/span&gt;] = user;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;  123&lt;/span&gt;             postData[&lt;span style="color:maroon;"&gt;"pwd"&lt;/span&gt;] = pwd;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;  124&lt;/span&gt;             postData[&lt;span style="color:maroon;"&gt;"dologin"&lt;/span&gt;] = &lt;span style="color:maroon;"&gt;"yes"&lt;/span&gt;;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;  125&lt;/span&gt; &lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;  126&lt;/span&gt;             &lt;span style="color:green;"&gt;//Create request and prepare Data&lt;/span&gt;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;  127&lt;/span&gt;             &lt;span style="color:teal;"&gt;HttpRequestWrapper&lt;/span&gt; request = &lt;span style="color:teal;"&gt;RequestFunctions&lt;/span&gt;.CreateRequest(uri,&lt;br /&gt;                                                                            postData,&lt;br /&gt;                                                                            ua);&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;  128&lt;/span&gt; &lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;  129&lt;/span&gt;             &lt;span style="color:green;"&gt;//Last tweaks to the request&lt;/span&gt;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;  130&lt;/span&gt;             &lt;span style="color:teal;"&gt;CookieContainer&lt;/span&gt; ckCont = &lt;span style="color:blue;"&gt;new&lt;/span&gt; &lt;span style="color:teal;"&gt;CookieContainer&lt;/span&gt;();&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;  131&lt;/span&gt;             request.CookieContainer = ckCont;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;  132&lt;/span&gt;             request.AllowAutoRedirect = &lt;span style="color:blue;"&gt;true&lt;/span&gt;;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;  133&lt;/span&gt;             &lt;span style="color:teal;"&gt;HttpWebResponse&lt;/span&gt; response = request.Post();&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;  134&lt;/span&gt;             &lt;span style="color:blue;"&gt;return&lt;/span&gt; ckCont.GetCookies(&lt;span style="color:blue;"&gt;new&lt;/span&gt; &lt;span style="color:teal;"&gt;Uri&lt;/span&gt;(uri));&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;  135&lt;/span&gt;         }&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;  136&lt;/span&gt; &lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;  137&lt;/span&gt;         &lt;span style="color:blue;"&gt;public&lt;/span&gt; &lt;span style="color:blue;"&gt;static&lt;/span&gt; &lt;span style="color:blue;"&gt;void&lt;/span&gt; StoreCookie(&lt;span style="color:teal;"&gt;CookieCollection&lt;/span&gt; ck, &lt;span style="color:blue;"&gt;string&lt;/span&gt; filePath)&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;  138&lt;/span&gt;         {&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;  139&lt;/span&gt;             &lt;span style="color:teal;"&gt;IFormatter&lt;/span&gt; formatter = &lt;span style="color:blue;"&gt;new&lt;/span&gt; &lt;span style="color:teal;"&gt;BinaryFormatter&lt;/span&gt;();&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;  140&lt;/span&gt;             &lt;span style="color:teal;"&gt;Stream&lt;/span&gt; outStream = &lt;span style="color:blue;"&gt;new&lt;/span&gt; &lt;span style="color:teal;"&gt;FileStream&lt;/span&gt;(filePath,&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;  141&lt;/span&gt;                                               &lt;span style="color:teal;"&gt;FileMode&lt;/span&gt;.Create,&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;  142&lt;/span&gt;                                               &lt;span style="color:teal;"&gt;FileAccess&lt;/span&gt;.Write,&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;  143&lt;/span&gt;                                               &lt;span style="color:teal;"&gt;FileShare&lt;/span&gt;.None);&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;  144&lt;/span&gt;             formatter.Serialize(outStream, ck);&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;  145&lt;/span&gt;             outStream.Close();&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;  146&lt;/span&gt;         }&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;  147&lt;/span&gt; &lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;  148&lt;/span&gt;         &lt;span style="color:blue;"&gt;public&lt;/span&gt; &lt;span style="color:blue;"&gt;static&lt;/span&gt; &lt;span style="color:teal;"&gt;CookieCollection&lt;/span&gt; RetrieveCookie(&lt;span style="color:blue;"&gt;string&lt;/span&gt; filePath)&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;  149&lt;/span&gt;         {&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;  150&lt;/span&gt;             &lt;span style="color:teal;"&gt;IFormatter&lt;/span&gt; formatter = &lt;span style="color:blue;"&gt;new&lt;/span&gt; &lt;span style="color:teal;"&gt;BinaryFormatter&lt;/span&gt;();&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;  151&lt;/span&gt;             &lt;span style="color:teal;"&gt;Stream&lt;/span&gt; iStream = &lt;span style="color:blue;"&gt;new&lt;/span&gt; &lt;span style="color:teal;"&gt;FileStream&lt;/span&gt;(filePath,&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;  152&lt;/span&gt;                                             &lt;span style="color:teal;"&gt;FileMode&lt;/span&gt;.Open,&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;  153&lt;/span&gt;                                             &lt;span style="color:teal;"&gt;FileAccess&lt;/span&gt;.Read,&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;  154&lt;/span&gt;                                             &lt;span style="color:teal;"&gt;FileShare&lt;/span&gt;.Read);&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;  155&lt;/span&gt;             &lt;span style="color:teal;"&gt;CookieCollection&lt;/span&gt; ck = (&lt;span style="color:teal;"&gt;CookieCollection&lt;/span&gt;)formatter.Deserialize(iStream);&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;  156&lt;/span&gt;             &lt;span style="color:blue;"&gt;return&lt;/span&gt; ck;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;  157&lt;/span&gt;         }&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;  158&lt;/span&gt; &lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;  159&lt;/span&gt; &lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;  160&lt;/span&gt; &lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;  161&lt;/span&gt; &lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;  162&lt;/span&gt; &lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;  163&lt;/span&gt;     }&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;  164&lt;/span&gt; &lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;  165&lt;/span&gt; &lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;  166&lt;/span&gt; }&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Comments&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;You take the low road, and I'll take the high road...&lt;/span&gt;&lt;br /&gt;.NET offers two ways of retrieving remote websites via HTTP. &lt;a href="http://msdn2.microsoft.com/en-us/library/system.net.httpwebrequest%28vs.80%29.aspx"&gt;System.Net.HttpWebRequest&lt;/a&gt; and &lt;a href="http://msdn2.microsoft.com/en-us/library/system.net.webclient%28vs.80%29.aspx"&gt;System.Net.WebClient&lt;/a&gt;. &lt;span style="font-family:courier new;"&gt;WebClient&lt;/span&gt; is very high level and handy for simple tasks; unfortunately, storing cookies isn't something it can do. This is where &lt;span style="font-family:courier new;"&gt;HttpWebRequest&lt;/span&gt; comes in.&lt;br /&gt;It can perform the tasks needed, but not overly well. To be honest, I was a bit appalled at how limited &lt;span style="font-family:courier new;"&gt;HttpWebRequest&lt;/span&gt; was.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Url encoding query strings&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;HttpWebRequest&lt;/span&gt; can't do this. The only functionality for encoding uri strings is located in &lt;a href="http://msdn2.microsoft.com/en-us/library/4fkewx0t%28VS.80%29.aspx"&gt;System.Web.HttpUtility.UrlEncode&lt;/a&gt; - System.Web is aimed at server side ASP.NET more than client side stuff like this and requires that you add a reference to the assembly. It's somewhat limited - it can only encode a string - so passing in mappings of names to values and getting an encoded string returned is not possible.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Sending the POST data&lt;/span&gt;&lt;br /&gt;Once again, &lt;span style="font-family:courier new;"&gt;HttpWebRequest&lt;/span&gt; doesn't know how to do this. I'm sure there are very good reasons why not, but it's a bit frustrating. So, once I've taken my data, and uri encoded it, I then have to convert it to a series of bytes to POST to the server.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Subclassing HttpWebRequest&lt;/span&gt;&lt;br /&gt;And this is where I decided I was going to subclass. All I wanted to add was a method  to encode a generic &lt;span style="font-family:courier new;"&gt;Dictionary&lt;string,&gt;&lt;/string,&gt;&lt;/span&gt; passed to it, and a method to handle the minor details of actually POSTing the data. And that's when I learnt about the &lt;span style="font-family:courier new;"&gt;internal &lt;/span&gt;keyword.&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;HttpWebRequest&lt;/span&gt; has multiple constructors. The one I needed to call was marked &lt;span style="font-family:courier new;"&gt;internal&lt;/span&gt; - that is, it can only be called by code residing in the same assembly. One of the &lt;a href="http://msdn2.microsoft.com/en-us/library/system.net.httpwebrequest.httpwebrequest%28VS.80%29.aspx"&gt;constructors is accessible&lt;/a&gt;, but it's an obsolete one that provides no required functionality. I ended up going with the wrapper approach - which feels like an ugly hack, but will save me from replicating the same code over and over as I proceed.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Overall&lt;/span&gt;&lt;br /&gt;I was quite disappointed with &lt;span style="font-family:courier new;"&gt;HttpWebReques&lt;/span&gt;t in some places - in others, I was pleased, for example, AllowAutoRedirect is a nice touch, in Python's urllib2, for example, you have no choice.  Serialising objects was straightforward, and the documentation, overall, was reasonably thorough. Some more relevant examples would always be nice, but that's MSDN for you.&lt;br /&gt;&lt;br /&gt;I'm still not happy about having to wrap a class when subclassing it would've been a lot simpler and neater - it's a bit of a horrible hack, because each time I need another property of &lt;span style="font-family:courier new;"&gt;HttpWebRequest&lt;/span&gt;, I'll have to add another property to &lt;span style="font-family:courier new;"&gt;HttpRequestWrapper.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;a style="font-weight: bold;" href="http://kunosure.blogspot.com/2007/05/unscientific-comparison-331-getting.html"&gt;&lt;span style="font-family: georgia;"&gt;Click here for Part 3.3.1&lt;/span&gt;&lt;/a&gt;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1724548057125197090-6705432038367026833?l=kunosure.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kunosure.blogspot.com/feeds/6705432038367026833/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1724548057125197090&amp;postID=6705432038367026833' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1724548057125197090/posts/default/6705432038367026833'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1724548057125197090/posts/default/6705432038367026833'/><link rel='alternate' type='text/html' href='http://kunosure.blogspot.com/2007/05/c.html' title='An unscientific comparison 3.3 - Getting the cookie, C#'/><author><name>Cynos</name><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-1724548057125197090.post-5491800374724102555</id><published>2007-05-18T22:09:00.000-07:00</published><updated>2007-06-04T16:27:55.471-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Scheme'/><title type='text'>An unscientific comparison 3.2 - Getting the cookie, Scheme</title><content type='html'>&lt;span style="font-weight: bold; font-style: italic;"&gt;Part 3.2 of N in a series. Click &lt;/span&gt;&lt;a style="font-weight: bold; font-style: italic;" href="http://kunosure.blogspot.com/2007/05/unscientific-comparison-31-getting.html"&gt;here&lt;/a&gt;&lt;span style="font-weight: bold; font-style: italic;"&gt; for part 3.1.&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;I must admit, writing this code took me the best part of an evening - mainly because of my inexperience in Scheme. I'm fine with prefix notation and the parentheses for Africa, it's merely that I lack the background knowledge to use Scheme properly - the background knowledge of idioms and usage patterns that one tends to acquire by osmosis. I'd like to comment that the residents of #Scheme on the Freenode IRC network are incredibly helpful, and very patient with dumb newbie question.&lt;br /&gt;&lt;br /&gt;&lt;style type="text/css"&gt;&lt;!--body.hl { background-color:#ffffff; }pre.hl { color:#000000; background-color:#ffffff; font-size:10pt; font-family:Courier New;border: 1px dashed #929292; padding-left: 5px; padding-top: 2px; padding-right: 5px; padding-bottom: 2px;}.hl.num { color:#2928ff; }.hl.esc { color:#ff00ff; }.hl.str { color:#FF0000; }.hl.dstr{ color:#818100; }.hl.slc { color:#838183; font-style:italic; }.hl.com { color:#838183; font-style:italic; }.hl.dir { color:#008200; }.hl.sym { color:#000000; font-weight:bold;}.hl.line { color:#555555; }.hl.kwa { color:#000099; font-weight:bold; }.hl.kwb { color:#770000; }.hl.kwc { color:#314F4F;}.hl.kwd { color:#000066;}//--&gt;&lt;/style&gt;So, the code using Felix Winkelmann's http library for Chicken Scheme.&lt;br /&gt;&lt;pre class="hl"&gt;&lt;br /&gt;&lt;span class="hl line"&gt; 1 &lt;/span&gt;(&lt;span class="hl kwa"&gt;require-extension&lt;/span&gt; &lt;span class="hl kwc"&gt;http-client&lt;/span&gt;)&lt;br /&gt;&lt;span class="hl line"&gt; 2 &lt;/span&gt;(&lt;span class="hl kwa"&gt;require-extension&lt;/span&gt; &lt;span class="hl kwc"&gt;srfi-13&lt;/span&gt;) &lt;span class="hl slc"&gt;;string functions&lt;/span&gt;&lt;br /&gt;&lt;span class="hl line"&gt; 3 &lt;/span&gt;(&lt;span class="hl kwa"&gt;require-extension&lt;/span&gt; &lt;span class="hl kwc"&gt;srfi-8&lt;/span&gt;) &lt;span class="hl slc"&gt;;receive statement&lt;/span&gt;&lt;br /&gt;&lt;span class="hl line"&gt; 4 &lt;/span&gt;(&lt;span class="hl kwa"&gt;require-extension&lt;/span&gt; &lt;span class="hl kwc"&gt;srfi-16&lt;/span&gt;) &lt;span class="hl slc"&gt;;case-lambda&lt;/span&gt;&lt;br /&gt;&lt;span class="hl line"&gt; 5 &lt;/span&gt;&lt;br /&gt;&lt;span class="hl line"&gt; 6 &lt;/span&gt;(&lt;span class="hl kwa"&gt;define&lt;/span&gt; &lt;span class="hl kwd"&gt;create-request&lt;/span&gt;&lt;br /&gt;&lt;span class="hl line"&gt; 7 &lt;/span&gt;  (&lt;span class="hl kwa"&gt;case&lt;/span&gt;-&lt;span class="hl kwa"&gt;lambda&lt;/span&gt;&lt;br /&gt;&lt;span class="hl line"&gt; 8 &lt;/span&gt;    ((method uri user-agent) (&lt;span class="hl kwc"&gt;http&lt;/span&gt;:&lt;span class="hl kwd"&gt;make-request&lt;/span&gt; method&lt;br /&gt;                          uri &lt;span class="hl kwa"&gt;&lt;br /&gt;                          `&lt;/span&gt;((&lt;span class="hl str"&gt;"User-Agent"&lt;/span&gt; . ,user-agent))))&lt;br /&gt;&lt;span class="hl line"&gt; 9 &lt;/span&gt;    ((method uri data user-agent)&lt;br /&gt;&lt;span class="hl line"&gt;10 &lt;/span&gt;     (&lt;span class="hl kwa"&gt;let&lt;/span&gt; ((encoded-data (&lt;span class="hl kwd"&gt;uri-encode-query&lt;/span&gt; data)))&lt;br /&gt;&lt;span class="hl line"&gt;11 &lt;/span&gt;       (&lt;span class="hl kwc"&gt;http&lt;/span&gt;:&lt;span class="hl kwd"&gt;make-request&lt;/span&gt; method&lt;br /&gt;&lt;span class="hl line"&gt;12 &lt;/span&gt;                          uri&lt;br /&gt;&lt;span class="hl line"&gt;13 &lt;/span&gt;                          `((&lt;span class="hl str"&gt;"User-Agent"&lt;/span&gt; . ,user-agent)&lt;br /&gt;&lt;span class="hl line"&gt;14 &lt;/span&gt;                            (&lt;span class="hl str"&gt;"Content-Type"&lt;/span&gt; . &lt;span class="hl str"&gt;"application/x-www-form-urlencoded"&lt;/span&gt;)&lt;br /&gt;&lt;span class="hl line"&gt;15 &lt;/span&gt;                            (&lt;span class="hl str"&gt;"Content-Length"&lt;/span&gt; . ,(&lt;span class="hl kwd"&gt;string-length&lt;/span&gt; encoded-data)))&lt;br /&gt;&lt;span class="hl line"&gt;16 &lt;/span&gt;                          encoded-data)))))&lt;br /&gt;&lt;span class="hl line"&gt;17 &lt;/span&gt;&lt;br /&gt;&lt;span class="hl line"&gt;18 &lt;/span&gt;&lt;br /&gt;&lt;span class="hl line"&gt;19 &lt;/span&gt;(&lt;span class="hl kwa"&gt;define&lt;/span&gt; (&lt;span class="hl kwd"&gt;get-cookie&lt;/span&gt; user pwd uri user-agent)&lt;br /&gt;&lt;span class="hl line"&gt;20 &lt;/span&gt;  (&lt;span class="hl kwa"&gt;let*&lt;/span&gt; ((data `((&lt;span class="hl str"&gt;"id"&lt;/span&gt; . ,user) (&lt;span class="hl str"&gt;"pwd"&lt;/span&gt; . ,pwd) (&lt;span class="hl str"&gt;"dologin"&lt;/span&gt; . &lt;span class="hl str"&gt;"yes"&lt;/span&gt;)))&lt;br /&gt;&lt;span class="hl line"&gt;21 &lt;/span&gt;        (auth-req (&lt;span class="hl kwd"&gt;create-request&lt;/span&gt; &lt;span class="hl kwb"&gt;'POST&lt;/span&gt; uri data user-agent)))&lt;br /&gt;&lt;span class="hl line"&gt;22 &lt;/span&gt;    (&lt;span class="hl kwa"&gt;receive&lt;/span&gt; (a header-list b c) (&lt;span class="hl kwc"&gt;http&lt;/span&gt;:&lt;span class="hl kwd"&gt;send-request&lt;/span&gt; auth-req) &lt;span class="hl slc"&gt;;Request A&lt;/span&gt;&lt;br /&gt;&lt;span class="hl line"&gt;23 &lt;/span&gt;             (&lt;span class="hl kwa"&gt;let&lt;/span&gt; ((cookie-req  (&lt;span class="hl kwd"&gt;create-request&lt;/span&gt; &lt;span class="hl kwb"&gt;'GET&lt;/span&gt;&lt;span class="hl line"&gt;&lt;br /&gt;24 &lt;/span&gt;                                                (&lt;span class="hl kwd"&gt;alist-ref&lt;/span&gt; &lt;span class="hl str"&gt;"location"&lt;/span&gt;&lt;br /&gt;                                                          header-list &lt;span class="hl kwd"&gt;&lt;br /&gt;                                                          equal?&lt;/span&gt;)&lt;br /&gt;&lt;span class="hl line"&gt;25 &lt;/span&gt;                                                 user-agent)))&lt;br /&gt;&lt;span class="hl line"&gt;26 &lt;/span&gt;               (&lt;span class="hl kwc"&gt;http&lt;/span&gt;:&lt;span class="hl kwd"&gt;GET&lt;/span&gt; cookie-req) &lt;span class="hl slc"&gt;;Request B&lt;/span&gt;&lt;br /&gt;&lt;span class="hl line"&gt;27 &lt;/span&gt;               (&lt;span class="hl kwd"&gt;alist-ref&lt;/span&gt; &lt;span class="hl str"&gt;"Cookie"&lt;/span&gt; (http:&lt;span class="hl kwd"&gt;request-attributes&lt;/span&gt; cookie-req) &lt;span class="hl kwd"&gt;equal?&lt;/span&gt;)))))&lt;br /&gt;&lt;span class="hl line"&gt;28 &lt;/span&gt;&lt;br /&gt;&lt;span class="hl line"&gt;29 &lt;/span&gt;&lt;br /&gt;&lt;span class="hl line"&gt;30 &lt;/span&gt;(&lt;span class="hl kwa"&gt;define&lt;/span&gt; (&lt;span class="hl kwd"&gt;store-cookie&lt;/span&gt; cookie file-path)&lt;br /&gt;&lt;span class="hl line"&gt;31 &lt;/span&gt;  (&lt;span class="hl kwa"&gt;let&lt;/span&gt; ((f (&lt;span class="hl kwd"&gt;open-output-file&lt;/span&gt; file-path)))&lt;br /&gt;&lt;span class="hl line"&gt;32 &lt;/span&gt;    (&lt;span class="hl kwd"&gt;write&lt;/span&gt; cookie f)&lt;br /&gt;&lt;span class="hl line"&gt;33 &lt;/span&gt;    (&lt;span class="hl kwd"&gt;close-output-port&lt;/span&gt; f)))&lt;br /&gt;&lt;span class="hl line"&gt;34 &lt;/span&gt;&lt;br /&gt;&lt;span class="hl line"&gt;35 &lt;/span&gt;&lt;br /&gt;&lt;span class="hl line"&gt;36 &lt;/span&gt;(&lt;span class="hl kwa"&gt;define&lt;/span&gt; (&lt;span class="hl kwd"&gt;retrieve-cookie&lt;/span&gt; file-path)&lt;br /&gt;&lt;span class="hl line"&gt;37 &lt;/span&gt;  (&lt;span class="hl kwa"&gt;let*&lt;/span&gt; ((f (&lt;span class="hl kwd"&gt;open-input-file&lt;/span&gt; file-path))&lt;br /&gt;&lt;span class="hl line"&gt;38 &lt;/span&gt;         (cookie (&lt;span class="hl kwd"&gt;read&lt;/span&gt; f)))&lt;br /&gt;&lt;span class="hl line"&gt;39 &lt;/span&gt;    (&lt;span class="hl kwd"&gt;close-input-port&lt;/span&gt; f)&lt;br /&gt;&lt;span class="hl line"&gt;40 &lt;/span&gt;    cookie))&lt;br /&gt;&lt;/pre&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;Comments&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Documentation&lt;/span&gt;&lt;br /&gt;The documentation for the http library covers all the bases - my only quibble would be a lack of examples, but that's a tiny quibble that arises only from my inexperience.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Data structures&lt;/span&gt;&lt;br /&gt;&lt;div style="text-align: left;"&gt;I had a bit of hassle with using &lt;a href="http://gd.tuwien.ac.at/languages/scheme/tutorial-dsitaram/t-y-scheme-Z-H-10.html"&gt;alist&lt;/a&gt;&lt;a href="http://gd.tuwien.ac.at/languages/scheme/tutorial-dsitaram/t-y-scheme-Z-H-10.html"&gt;s&lt;/a&gt; - the default &lt;a href="http://www.cs.aau.dk/%7Enormark/prog3-03/external-material/r5rs/r5rs-html/r5rs_48.html"&gt;predicate for equivalence&lt;/a&gt; used by the built-in function for alist item retrieval, &lt;span style="font-family:courier new;"&gt;assv&lt;/span&gt;, &lt;span style="font-family:courier new;"&gt;&lt;/span&gt;is&lt;span style="font-family:courier new;"&gt; eqv?&lt;/span&gt; - which returns false for &lt;span style="font-family:courier new;"&gt;"test" == "test"&lt;/span&gt;. Chicken Scheme comes with some &lt;a href="http://galinha.ucpel.tche.br:8080//Unit%20extras#Unit%20extras"&gt;extra functions&lt;/a&gt; that I'd most likely end up writing if using R5RS Scheme, one of which is &lt;span style="font-family:courier new;"&gt;alist-ref&lt;/span&gt;, which allows me to specify that the predicate to be used is &lt;span style="font-family:courier new;"&gt;equal?&lt;/span&gt; which returns true for "&lt;span style="font-family:courier new;"&gt;test" == "test". &lt;/span&gt;(And also for "&lt;span style="font-family:courier new;"&gt;TEST" == "test"&lt;/span&gt;, this could be problematic in certain situations, but is fine here) Learning how to compose an alist inline was interesting, backquoting and comma prefixing all over the show.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;File IO&lt;/span&gt;&lt;br /&gt;Reading and writing to/from a file was relatively painless compared to my experiences in Lisp.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;SRFIs&lt;br /&gt;&lt;/span&gt;The SRFIs are great, but a little obscure at first. It's become clear to me that I'll need to become familiar with their contents if I'm to make effective use of Scheme.&lt;span style="font-weight: bold;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Overall&lt;br /&gt;&lt;/span&gt;Using the &lt;a href="http://www.call-with-current-continuation.org/eggs/http.html"&gt;http&lt;/a&gt; library ended up being a little lower level than I had anticipated, mainly because my usage fell outside of the common usages for which convenience functions existed - for instance, instead of building a request for posting and setting Content-Length headers myself, I could've used http:POST, which would've done all of that, but it only returns the body of the response, when I needed the header to follow the redirect. (Request A returns a 302 response, request B actually gets the cookie.) I did note that &lt;span style="font-family:courier new;"&gt;http:POST&lt;/span&gt; doesn't urlencode the datapassed to it, however, and I had to write a wee socket server in Erlang to confirm that. Not a bug, just something to note.&lt;br /&gt;&lt;br /&gt;I learnt a fair bit about Scheme in doing this, and the support from the Scheme IRC residents on Freenode, both #Scheme and #Chicken, was fantastic. I quite enjoyed myself, and this is exactly why I chose this method - "sink or swim" seems to be the best way to learn a language and its environment quickly.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;a style="font-weight: bold;" href="http://kunosure.blogspot.com/2007/05/c.html"&gt;Click here for Part 3.3&lt;/a&gt;&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1724548057125197090-5491800374724102555?l=kunosure.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kunosure.blogspot.com/feeds/5491800374724102555/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1724548057125197090&amp;postID=5491800374724102555' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1724548057125197090/posts/default/5491800374724102555'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1724548057125197090/posts/default/5491800374724102555'/><link rel='alternate' type='text/html' href='http://kunosure.blogspot.com/2007/05/unscientific-comparison-32-getting.html' title='An unscientific comparison 3.2 - Getting the cookie, Scheme'/><author><name>Cynos</name><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-1724548057125197090.post-8085741311224573138</id><published>2007-05-15T18:49:00.000-07:00</published><updated>2007-06-04T16:46:17.571-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Python'/><title type='text'>An unscientific comparison 3.1 - Getting the cookie, Python</title><content type='html'>&lt;span style="font-weight: bold; font-style: italic;"&gt;Part 3.1 of N in a series. Click &lt;/span&gt;&lt;a style="font-weight: bold; font-style: italic;" href="http://kunosure.blogspot.com/2007/05/unscientific-comparison-getting-cookies.html"&gt;here&lt;/a&gt;&lt;span style="font-weight: bold; font-style: italic;"&gt; for Part 3.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;So, without further ado, here's some actual code. I've started with Python as it's my 'default' language.&lt;br /&gt;&lt;style type="text/css"&gt;&lt;!--body.hl { background-color:#ffffff; }pre.hl { color:#000000; background-color:#ffffff; font-size:10pt; font-family:Courier New;border: 1px dashed #929292; padding-left: 5px; padding-top: 2px; padding-right: 5px; padding-bottom: 2px;}.hl.num { color:#2928ff; }.hl.esc { color:#ff00ff; }.hl.str { color:#FF0000; }.hl.dstr{ color:#818100; }.hl.slc { color:#838183; font-style:italic; }.hl.com { color:#838183; font-style:italic; }.hl.dir { color:#008200; }.hl.sym { color:#000000; font-weight:bold;}.hl.line { color:#555555; }.hl.kwa { color:#000099; font-weight:bold; }.hl.kwb { color:#770000; }.hl.kwc { color:#314F4F;}.hl.kwd { color:#000066;}//--&gt;&lt;/style&gt;&lt;br /&gt;&lt;pre class="hl"&gt;&lt;span class="hl line"&gt; 1 &lt;/span&gt;&lt;span class="hl kwa"&gt;import&lt;/span&gt; &lt;span class="hl kwc"&gt;urllib&lt;/span&gt;&lt;br /&gt;&lt;span class="hl line"&gt; 2 &lt;/span&gt;&lt;span class="hl kwa"&gt;import&lt;/span&gt; &lt;span class="hl kwc"&gt;urllib2&lt;/span&gt;&lt;br /&gt;&lt;span class="hl line"&gt; 3 &lt;/span&gt;&lt;span class="hl kwa"&gt;import&lt;/span&gt; &lt;span class="hl kwc"&gt;cookielib&lt;/span&gt;&lt;br /&gt;&lt;span class="hl line"&gt; 4 &lt;/span&gt;&lt;br /&gt;&lt;span class="hl line"&gt; 5 &lt;/span&gt;&lt;span class="hl kwa"&gt;def&lt;/span&gt; &lt;span class="hl kwd"&gt;getCookie&lt;/span&gt;&lt;span class="hl sym"&gt;(&lt;/span&gt;user&lt;span class="hl sym"&gt;,&lt;/span&gt; pwd&lt;span class="hl sym"&gt;,&lt;/span&gt; uri&lt;span class="hl sym"&gt;,&lt;/span&gt; ua&lt;span class="hl sym"&gt;):&lt;/span&gt;&lt;br /&gt;&lt;span class="hl line"&gt; 6 &lt;/span&gt;    ckCont &lt;span class="hl sym"&gt;=&lt;/span&gt; &lt;span class="hl kwc"&gt;cookielib&lt;/span&gt;&lt;span class="hl sym"&gt;.&lt;/span&gt;&lt;span class="hl kwd"&gt;LWPCookieJar&lt;/span&gt;&lt;span class="hl sym"&gt;()&lt;/span&gt;&lt;br /&gt;&lt;span class="hl line"&gt; 7 &lt;/span&gt;    opener &lt;span class="hl sym"&gt;=&lt;/span&gt; &lt;span class="hl kwc"&gt;urllib2&lt;/span&gt;&lt;span class="hl sym"&gt;.&lt;/span&gt;&lt;span class="hl kwd"&gt;build_opener&lt;/span&gt;&lt;span class="hl sym"&gt;(&lt;/span&gt;&lt;span class="hl kwc"&gt;urllib2&lt;/span&gt;&lt;span class="hl sym"&gt;.&lt;/span&gt;&lt;span class="hl kwd"&gt;HTTPCookieProcessor&lt;/span&gt;&lt;span class="hl sym"&gt;(&lt;/span&gt;ckCont&lt;span class="hl sym"&gt;))&lt;/span&gt;&lt;br /&gt;&lt;span class="hl line"&gt; 8 &lt;/span&gt;    opener&lt;span class="hl sym"&gt;.&lt;/span&gt;addheaders &lt;span class="hl sym"&gt;= [(&lt;/span&gt;&lt;span class="hl str"&gt;'User-Agent'&lt;/span&gt;&lt;span class="hl sym"&gt;,&lt;/span&gt; ua&lt;span class="hl sym"&gt;)]&lt;/span&gt;&lt;br /&gt;&lt;span class="hl line"&gt; 9 &lt;/span&gt;    data &lt;span class="hl sym"&gt;=&lt;/span&gt; &lt;span class="hl kwc"&gt;urllib&lt;/span&gt;&lt;span class="hl sym"&gt;.&lt;/span&gt;&lt;span class="hl kwd"&gt;urlencode&lt;/span&gt;&lt;span class="hl sym"&gt;({&lt;/span&gt;&lt;span class="hl str"&gt;'id'&lt;/span&gt;&lt;span class="hl sym"&gt;:&lt;/span&gt;user&lt;span class="hl sym"&gt;,&lt;/span&gt; &lt;span class="hl str"&gt;'pwd'&lt;/span&gt;&lt;span class="hl sym"&gt;:&lt;/span&gt; pwd&lt;span class="hl sym"&gt;,&lt;/span&gt; &lt;span class="hl str"&gt;'dologin'&lt;/span&gt;&lt;span class="hl sym"&gt;:&lt;/span&gt; &lt;span class="hl str"&gt;'yes'&lt;/span&gt;&lt;span class="hl sym"&gt;})&lt;/span&gt;&lt;br /&gt;&lt;span class="hl line"&gt;10 &lt;/span&gt;    opener&lt;span class="hl sym"&gt;.&lt;/span&gt;&lt;span class="hl kwd"&gt;open&lt;/span&gt;&lt;span class="hl sym"&gt;(&lt;/span&gt;uri&lt;span class="hl sym"&gt;,&lt;/span&gt; data&lt;span class="hl sym"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class="hl line"&gt;11 &lt;/span&gt;    &lt;span class="hl kwa"&gt;return&lt;/span&gt; ckCont&lt;br /&gt;&lt;span class="hl line"&gt;12 &lt;/span&gt;&lt;br /&gt;&lt;span class="hl line"&gt;13 &lt;/span&gt;&lt;span class="hl kwa"&gt;def&lt;/span&gt; &lt;span class="hl kwd"&gt;storeCookie&lt;/span&gt;&lt;span class="hl sym"&gt;(&lt;/span&gt;ck&lt;span class="hl sym"&gt;,&lt;/span&gt; file_path&lt;span class="hl sym"&gt;):&lt;/span&gt;&lt;br /&gt;&lt;span class="hl line"&gt;14&lt;/span&gt;&lt;span class="hl line"&gt; &lt;/span&gt;    ck&lt;span class="hl sym"&gt;.&lt;/span&gt;&lt;span class="hl kwd"&gt;save&lt;/span&gt;&lt;span class="hl sym"&gt;(&lt;/span&gt;file_path&lt;span class="hl sym"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class="hl line"&gt;15 &lt;/span&gt;&lt;br /&gt;&lt;span class="hl line"&gt;16 &lt;/span&gt;&lt;span class="hl kwa"&gt;def&lt;/span&gt; &lt;span class="hl kwd"&gt;retrieveCookie&lt;/span&gt;&lt;span class="hl sym"&gt;(&lt;/span&gt;file_path&lt;span class="hl sym"&gt;):&lt;/span&gt;&lt;br /&gt;&lt;span class="hl line"&gt;17&lt;/span&gt;&lt;span class="hl line"&gt; &lt;/span&gt;    ckCont &lt;span class="hl sym"&gt;=&lt;/span&gt; &lt;span class="hl kwc"&gt;cookielib&lt;/span&gt;&lt;span class="hl sym"&gt;.&lt;/span&gt;&lt;span class="hl kwd"&gt;LWPCookieJar&lt;/span&gt;&lt;span class="hl sym"&gt;(&lt;/span&gt;file_path&lt;span class="hl sym"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class="hl line"&gt;18&lt;/span&gt;&lt;span class="hl line"&gt; &lt;/span&gt;    ckCont&lt;span class="hl sym"&gt;.&lt;/span&gt;&lt;span class="hl kwd"&gt;load&lt;/span&gt;&lt;span class="hl sym"&gt;()&lt;br /&gt;&lt;/span&gt;&lt;span class="hl line"&gt;19&lt;/span&gt;&lt;span class="hl line"&gt; &lt;/span&gt;    &lt;span class="hl kwa"&gt;return&lt;/span&gt; ckCont&lt;br /&gt;&lt;/pre&gt;&lt;span style="font-weight: bold;"&gt;&lt;span style="font-size:130%;"&gt;Comments&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-size:100%;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:100%;"&gt;&lt;span style="font-weight: bold;"&gt;Duplicate libraries&lt;/span&gt;&lt;br /&gt;This is one of the messier areas of the stdlib in my mind, and I'm hoping it gets overhauled for Python 3000. If it's not currently planned, I should probably volunteer. Both &lt;a href="http://docs.python.org/lib/module-urllib.html"&gt;&lt;span style="font-family:courier new;"&gt;urllib&lt;/span&gt;&lt;/a&gt; and &lt;a href="http://docs.python.org/lib/module-urllib2.html"&gt;&lt;span style="font-family:courier new;"&gt;urllib2&lt;/span&gt;&lt;/a&gt;  have similar functionality with regards to the HTTP protocol, but only&lt;span style="font-family:courier new;"&gt; urllib2&lt;/span&gt; has the capacity to handle cookies and proxies sanely. The only thing &lt;span style="font-family:courier new;"&gt;urllib&lt;/span&gt; is really necessary for (in my experience) is &lt;span style="font-family:courier new;"&gt;urlencode&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Documentation&lt;/span&gt;&lt;br /&gt;The documentation for &lt;span style="font-family:courier new;"&gt;urllib2&lt;/span&gt; is... sparse. Some more examples would've been brilliant, as would've some clarification of what needs to go with what. For instance, I'm assuming a proxy requiring login will need a ProxyHandler and a BasicProxyAuthHandler, but such (I'd assume) common usages aren't commented on. Perhaps something else I should volunteer to correct.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;&lt;span style="font-weight: bold;"&gt;Edit:&lt;/span&gt; A commenter pointed out these two great resources: &lt;/span&gt;&lt;a style="font-style: italic;" href="http://www.voidspace.org.uk/python/articles/urllib2.shtml"&gt;urllib2 - The Missing Manual&lt;/a&gt;&lt;span style="font-style: italic;"&gt; and &lt;/span&gt;&lt;a style="font-style: italic;" href="http://www.voidspace.org.uk/python/articles/cookielib.shtml"&gt;cookielib and ClientCookie&lt;/a&gt;&lt;span style="font-style: italic;"&gt;. Seems someone else is way ahead of me in that respect.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Out-and-out broken libraries&lt;/span&gt;&lt;br /&gt;I had to upgrade to Python 2.5.1 to make this work, as urllib2 in Python 2.4 is apparently broken when trying to use cookie handlers, and my experiences with it anecdotally confirm that. First time I've ever encountered that in Python...&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Minor quibble&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-size:100%;"&gt;&lt;span style="font-family:courier new;"&gt;opener.addheaders&lt;/span&gt; - phrased like a method, it's actually a property, a list of headers to add. I know it's more verbose, but perhaps it should be called headersToAdd.&lt;br /&gt;&lt;span style="font-style: italic;"&gt;&lt;span style="font-weight: bold;"&gt;Edit:&lt;/span&gt; I did have another quibble here about CookieJars not being serialisable, but with LWPCookieJar, I don't need to serialise anything.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;Overall&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size:100%;"&gt;&lt;span style="font-family:courier new;"&gt;urllib2&lt;/span&gt; is quite an indepth library, and handles moderately complex behaviour reasonably well, especially when the ability to 'chain' handlers to build a custom opener is used - as I've done with the cookie handler. It also automates some of the mucking around, which is always nice, although it does add a trace of 'magic' to the code. For example, in the above code, there are actually two requests made - if the initial &lt;span style="font-family:courier new;"&gt;POST&lt;/span&gt; is successful, a HTTP 302 (Object moved) response is returned, with a header pointing to a new URI which sets the authentication cookie. Urllib2 sends the &lt;span style="font-family:courier new;"&gt;GET&lt;/span&gt; to this new location without prompting.&lt;br /&gt;&lt;br /&gt;While the documentation is a bit bare, it's still more fleshed out than an auto-generated API document. That said, needs work, needs work.&lt;br /&gt;&lt;br /&gt;The code feels reasonably concise, and fairly self-documenting. The only part that could be confusing is how the cookie is getting into the CookieJar. (&lt;span style="font-family:courier new;"&gt;opener&lt;/span&gt; stuck it there).&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;a style="font-weight: bold;" href="http://kunosure.blogspot.com/2007/05/unscientific-comparison-32-getting.html"&gt;Click here for Part 3.2, the Scheme version&lt;/a&gt;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1724548057125197090-8085741311224573138?l=kunosure.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kunosure.blogspot.com/feeds/8085741311224573138/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1724548057125197090&amp;postID=8085741311224573138' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1724548057125197090/posts/default/8085741311224573138'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1724548057125197090/posts/default/8085741311224573138'/><link rel='alternate' type='text/html' href='http://kunosure.blogspot.com/2007/05/unscientific-comparison-31-getting.html' title='An unscientific comparison 3.1 - Getting the cookie, Python'/><author><name>Cynos</name><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-1724548057125197090.post-8729157348425450117</id><published>2007-05-13T03:17:00.000-07:00</published><updated>2007-06-05T21:34:47.879-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='Rebol'/><category scheme='http://www.blogger.com/atom/ns#' term='XPCOM'/><category scheme='http://www.blogger.com/atom/ns#' term='Scheme'/><category scheme='http://www.blogger.com/atom/ns#' term='Prolog'/><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='Lisp'/><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><category scheme='http://www.blogger.com/atom/ns#' term='IronPython'/><category scheme='http://www.blogger.com/atom/ns#' term='Erlang'/><category scheme='http://www.blogger.com/atom/ns#' term='Python'/><category scheme='http://www.blogger.com/atom/ns#' term='Haskell'/><title type='text'>An unscientific comparison 3 - The first cookie</title><content type='html'>&lt;span style="font-style: italic; font-weight: bold;"&gt;Part 3 of N in a series, click &lt;/span&gt;&lt;a style="font-style: italic; font-weight: bold;" href="http://kunosure.blogspot.com/2007/05/unscientific-comparison-first-steps.html"&gt;here&lt;/a&gt;&lt;span style="font-style: italic; font-weight: bold;"&gt; for part 2.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;As the web app will require I use a cookie to authenticate, the first step is to retrieve from the server and store that cookie.&lt;br /&gt;&lt;br /&gt;Today, I want to write three functions - one that creates the cookie by logging in, one that stores it locally, and one that retrieves it. I won't be using the third one just yet, but it seems logical to get all the cookie related stuff out of the way. I'm keeping error handling simple - generally speaking, if one of these functions fails, it should let the calling context handle the failure.&lt;br /&gt;&lt;br /&gt;So, the spec. Incidentally, &lt;span style="font-family:courier new;"&gt;cookie&lt;/span&gt; can either be a single cookie or some kind of container object holding a cookie, I'm easy in that regard.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="font-weight: bold;"&gt;getCookie&lt;/span&gt;(&lt;span style="font-style: italic;"&gt;user&lt;/span&gt;, &lt;span style="font-style: italic;"&gt;password&lt;/span&gt;, &lt;span style="font-style: italic;"&gt;uri&lt;/span&gt;, &lt;span style="font-style: italic;"&gt;userAgent&lt;/span&gt;) &lt;span style="font-weight: bold;"&gt;returns&lt;/span&gt; &lt;span style="font-style: italic;"&gt;cookie&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;This POSTs the urlencoded user and password to the given uri, and sets the User-Agent header to the given userAgent if possible. The cookie from the HTTP response will be returned.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-family:courier new;" &gt;storeCookie&lt;/span&gt;&lt;span style="font-family:courier new;"&gt;(&lt;/span&gt;&lt;span style="font-style: italic;font-family:courier new;" &gt;cookie&lt;/span&gt;&lt;span style="font-family:courier new;"&gt;,&lt;/span&gt;&lt;span style="font-style: italic;font-family:courier new;" &gt; filePath&lt;/span&gt;&lt;span style="font-family:courier new;"&gt;)&lt;/span&gt;&lt;br /&gt;This stores the cookie in the given file. How the cookie is stored isn't specified, I prefer object serialisation, but if that's not possible, I can live with a text file. Nothing needs to be returned.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-family:courier new;" &gt;retrieveCookie&lt;/span&gt;&lt;span style="font-family:courier new;"&gt;(&lt;/span&gt;&lt;span style="font-style: italic;font-family:courier new;" &gt;filePath&lt;/span&gt;&lt;span style="font-family:courier new;"&gt;) &lt;/span&gt;&lt;span style="font-weight: bold;font-family:courier new;" &gt;returns&lt;/span&gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="font-style: italic;"&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style="font-style: italic;font-family:courier new;" &gt;cookie&lt;/span&gt;&lt;br /&gt;Opens the given file, and returns the cookie. If the file doesn't exist, then any exception or error should be handled by the calling context.&lt;br /&gt;&lt;br /&gt;I will add each implementation of this as a separate entry.&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Implementations&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-size:100%;"&gt;&lt;a href="http://kunosure.blogspot.com/2007/05/unscientific-comparison-31-getting.html"&gt;&lt;span style="font-weight: bold;"&gt;Part 3.1&lt;/span&gt; - Python&lt;/a&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-size:100%;"&gt;&lt;a href="http://kunosure.blogspot.com/2007/05/unscientific-comparison-32-getting.html"&gt;&lt;span style="font-weight: bold;"&gt;Part 3.2 &lt;/span&gt;- Scheme&lt;/a&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-size:100%;"&gt;&lt;a href="http://kunosure.blogspot.com/2007/05/c.html"&gt;&lt;span style="font-weight: bold;"&gt;Part 3.3&lt;/span&gt; - C#&lt;/a&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-size:100%;"&gt;&lt;a href="http://kunosure.blogspot.com/2007/05/unscientific-comparison-332-getting.html"&gt;&lt;span style="font-weight: bold;"&gt;Part 3.3.2 &lt;/span&gt;- C#, the right way&lt;/a&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;&lt;a href="http://kunosure.blogspot.com/2007/06/unscientific-comparison-34-getting.html"&gt;&lt;span style="font-weight: bold;"&gt;Part 3.4&lt;/span&gt; - Ruby&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://kunosure.blogspot.com/2007/06/unscientific-comparison-35-getting.html"&gt;&lt;span style="font-weight: bold;"&gt;Part 3.5&lt;/span&gt; - Haskell&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1724548057125197090-8729157348425450117?l=kunosure.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kunosure.blogspot.com/feeds/8729157348425450117/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1724548057125197090&amp;postID=8729157348425450117' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1724548057125197090/posts/default/8729157348425450117'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1724548057125197090/posts/default/8729157348425450117'/><link rel='alternate' type='text/html' href='http://kunosure.blogspot.com/2007/05/unscientific-comparison-getting-cookies.html' title='An unscientific comparison 3 - The first cookie'/><author><name>Cynos</name><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-1724548057125197090.post-4033367574779839176</id><published>2007-05-10T05:35:00.000-07:00</published><updated>2007-05-19T23:30:20.825-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='Rebol'/><category scheme='http://www.blogger.com/atom/ns#' term='XPCOM'/><category scheme='http://www.blogger.com/atom/ns#' term='Scheme'/><category scheme='http://www.blogger.com/atom/ns#' term='Prolog'/><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='Lisp'/><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><category scheme='http://www.blogger.com/atom/ns#' term='IronPython'/><category scheme='http://www.blogger.com/atom/ns#' term='Erlang'/><category scheme='http://www.blogger.com/atom/ns#' term='Python'/><category scheme='http://www.blogger.com/atom/ns#' term='Haskell'/><title type='text'>An unscientific comparison  2 - First steps</title><content type='html'>&lt;span style="font-style: italic; font-weight: bold;"&gt;Part 2 of N in a series. Click &lt;/span&gt;&lt;a style="font-style: italic; font-weight: bold;" href="http://kunosure.blogspot.com/2007/05/unscientific-comparison-of-programming.html"&gt;here&lt;/a&gt;&lt;span style="font-style: italic; font-weight: bold;"&gt; for part 1.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;So, first things first, let's download and install some programming languages.&lt;br /&gt;&lt;br /&gt;For 'monolithic' languages, that is, languages with one main distribution, I'll be using that. For languages with several available implementations, I'll choose the particular implementation based on several factors:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Is it free?&lt;/li&gt;&lt;li&gt;Does it work on Windows XP? (My current OS)&lt;/li&gt;&lt;li&gt;Does the standard library support HTTP out of the box?&lt;/li&gt;&lt;/ul&gt;The HTTP requirement is a simple one - I feel that any modern programming language should support the most common protocols as a matter of course. Also, I'm not looking to reimplement any RFCs here.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;How the installs compared&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Python&lt;/span&gt;&lt;br /&gt;All you really need to know to get started with Python is &lt;a href="http://www.blogger.com/www.python.org"&gt;www.python.org&lt;/a&gt; - the page contains documentation, official installation packages and links to unofficial packages such as ActiveState's &lt;a href="http://activestate.com/products/activepython/"&gt;ActivePython.&lt;/a&gt; At this point in time, when people think of Python, they're thinking of CPython - although as Microsoft's &lt;a href="http://blogs.msdn.com/hugunin/archive/2007/04/30/a-dynamic-language-runtime-dlr.aspx"&gt;DLR&lt;/a&gt;  becomes widespread, IronPython, as the flagship/testbed dynamic language may become more well known. Jython remains relatively obscure, and I can't foresee that changing. As such there's not likely to be much problem choosing CPython over the other two implementations - that said, I'm guessing a little, I know Python too well to accurately model a newbie.&lt;br /&gt;&lt;br /&gt;The only issue could be if you ignored the prominent links to download Python 2.5.1 on the main page and went digging through the Downloads page, you could find the link to ActivePython which could raise some questions as to what precisely to install - noting that ActivePython's page is pretty clear that it only contains some additional libraries and documentation.&lt;br /&gt;&lt;br /&gt;Once I'd downloaded my distribution (I actually went with ActivePython because I prefer its REPL), installation was simply a case of executing the installer.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Scheme (Chicken)&lt;/span&gt;&lt;br /&gt;Getting started with Scheme takes a bit more research.  As I'd become interested in Scheme after reading &lt;a href="http://mitpress.mit.edu/sicp/"&gt;SICP&lt;/a&gt; (and it's more easily accessible counterpart, &lt;a href="http://htdp.org/"&gt;How To Develop Programs&lt;/a&gt;), I began experimenting with PLT's &lt;a href="http://www.plt-scheme.org/software/drscheme/"&gt;DrScheme&lt;/a&gt;. However, DrScheme supports several different variations on Scheme - &lt;a href="http://www.schemers.org/Documents/Standards/R5RS/"&gt;standard R5RS&lt;/a&gt; Scheme, &lt;a href="http://www.plt-scheme.org/software/mzscheme/"&gt;MzScheme&lt;/a&gt;, a fuller featured implementation and &lt;a href="http://www.plt-scheme.org/software/mred/"&gt;MrEd,&lt;/a&gt; a graphical implementation. I wasn't quite sure which one of these I should use and to make a decision, I had to learn about how Scheme is 'managed' so to speak. I had initially assumed Scheme was monolithic like Python, but I soon found out I was wrong.&lt;br /&gt;&lt;br /&gt;I learnt that the core Scheme language was defined in the standard R5RS, but that R5RS Scheme was incredibly minimalistic, with most additional functionality being provided by the different implementations. So I started looking at the various options.... and I found &lt;a href="http://community.schemewiki.org/?scheme-faq-standards#implementations"&gt;this list of Scheme implementations&lt;/a&gt;...&lt;br /&gt;&lt;br /&gt;...I had no real way of assessing each implementation on it's merits, so I chose mainly on the standard library. The PLT Schemes supported sockets but not HTTP, ditto &lt;a href="http://www-sop.inria.fr/mimosa/fp/Bigloo/"&gt;Bigloo Scheme&lt;/a&gt;, but &lt;a href="http://www.call-with-current-continuation.org/"&gt;Chicken's&lt;/a&gt; "&lt;a href="http://www.call-with-current-continuation.org/eggs/"&gt;Eggs Unlimited&lt;/a&gt;" included an &lt;a href="http://www.call-with-current-continuation.org/eggs/http.html"&gt;http&lt;/a&gt; module. So Chicken it was.&lt;br /&gt;&lt;br /&gt;Installing Chicken was a bit different, me being the Windows user that I am, as it was only available as source code. The first step in configuring the install was to download and install &lt;a href="http://www.cmake.org/"&gt;CMake&lt;/a&gt;, a cross platform makefile generator. I initially used this to generate a Visual Studio project, which didn't compile... so I downloaded &lt;a href="http://www.mingw.org/"&gt;MinGW&lt;/a&gt;, and created makefiles for that. This time, the compilation went flawlessly. The hardest part was figuring out which MinGW file to download, but after a bit of trial and error, I figured it out, and even wrote a &lt;a href="http://galinha.ucpel.tche.br/cgi-bin/svnwiki/default/compiling-chicken-on-windows-xp-with-mingw"&gt;page&lt;/a&gt; on the Chicken wiki, for any other C newbies like me.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;C#&lt;/span&gt;&lt;br /&gt;I already had Visual Studio installed for  ASP.NET development, so everything I needed was included.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Ruby&lt;/span&gt;&lt;br /&gt;Determining what I needed was straightforward. &lt;a href="http://jruby.codehaus.org/"&gt;JRuby&lt;/a&gt; is approaching 1.0 release, I believe, not that I have much interest in the JVM,  and IronRuby is, for all intents, still a twinkle in &lt;a href="http://blogs.msdn.com/hugunin/archive/2007/04/30/a-dynamic-language-runtime-dlr.aspx"&gt;Jim Huginin's eye&lt;/a&gt;. So, downloading and running the Windows installer from the &lt;a href="http://www.ruby-lang.org/"&gt;Ruby page&lt;/a&gt;  is all I need.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Haskell&lt;/span&gt;&lt;br /&gt;Haskell has multiple implementations available, and after ten minutes on Wikipedia, I'd decided that either &lt;a href="http://www.cs.uu.nl/helium/"&gt;Helium&lt;/a&gt; or &lt;a href="http://www.haskell.org/hugs/"&gt;Hugs&lt;/a&gt; would be best. The question is, which one? Helium offers friendlier error messages apparently, but at the expense of some functionality - for instance, no type classes. Will I need a type class in this? After some further reading on &lt;a href="http://en.wikipedia.org/wiki/Type_polymorphism#Ad-hoc_polymorphism"&gt;Wikipedia&lt;/a&gt; and on the &lt;a href="http://www.cs.uu.nl/helium/HeliumDiffHaskell98.html"&gt;Helium page...&lt;/a&gt; I still don't know. I've decided to try Hugs first, and if I have any issues figuring out what I'm doing wrong, I'll try Helium then.&lt;br /&gt;&lt;br /&gt;Installing Hugs just requires I download and run an installer.&lt;br /&gt;&lt;span style="font-style: italic;"&gt;&lt;span style="font-weight: bold;"&gt;Edit: &lt;/span&gt;It has been suggested by a commenter that I stick with GHC; I shall take that advice, and have downloaded Visual Haskell, an alpha plugin for Visual Studio that ships with GHC. &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Common Lisp&lt;/span&gt;&lt;br /&gt;Common Lisp is like Scheme, in that there's a standard, and then several different implementations of that standard. After reading &lt;a href="http://www.cliki.net/Common%20Lisp%20implementation"&gt;Cliki&lt;/a&gt; and &lt;a href="http://wiki.alu.org/Implementation"&gt;ALUwiki&lt;/a&gt; and applying a couple of criteria (works on Windows, I don't have to buy it) I  have a a narrow list of possible implementations - &lt;a href="http://sbcl.sourceforge.net/"&gt;SBCL&lt;/a&gt;, &lt;a href="http://www.lispworks.com/"&gt;LispWorks&lt;/a&gt;, &lt;a href="http://www.franz.com/"&gt;Allegro&lt;/a&gt;, &lt;a href="http://www.cliki.net/CLISP"&gt;CLISP&lt;/a&gt;. After much researching of libraries etc. I've gone with LispWorks, mainly because the HTTP module I'm going to use, &lt;a href="http://weitz.de/drakma/"&gt;Drakma&lt;/a&gt;, was written for LispWorks and requires slightly less jiggery-pokey to get going. Also, the REPL is available within LispWorks, so no more cmd.exe REPLs or Emacs buffers! I'm quite pleased about that to be honest.&lt;br /&gt;&lt;br /&gt;Installing Drakma actually took a little more work. Most of it revolving around &lt;a href="http://www.cliki.net/asdf"&gt;ASDF&lt;/a&gt;. ASDF is a packaging system for Lisp. Now, there's a simpler interface to it called &lt;a href="http://www.cliki.net/ASDF-Install"&gt;ASDF-INSTALL&lt;/a&gt;, but it's *nix-centric, and I'm not  keen to go down the Cygwin path just yet.  I was stumped, to be honest. LispWorks didn't ship with ASDF, so the first step was to install it. By this stage, I'd thoroughly confused myself with the ASDF-INSTALL documentation, and had given up on being able to get ASDF up and running... I was experimenting with &lt;a href="http://weitz.de/rdnzl/"&gt;RDNZL&lt;/a&gt;, a wrapper between Common Lisp and .NET, my intention being to use .NET's WebRequest and WebResponse instead.&lt;br /&gt;&lt;br /&gt;Luckily, I'd started having a browse through the &lt;a href="http://weitz.de/"&gt;website of Edi Weitz&lt;/a&gt;, the author of both Drakma and RDNZL, and found his &lt;a href="http://weitz.de/starter-pack/"&gt;STARTER-PACK&lt;/a&gt;, specifically designed for Windows using newbies like me. It installed and configured ASDF for me, but also, it installed Dr Weitz's &lt;a href="http://weitz.de/lw-add-ons/"&gt;LW-ADD-ONS&lt;/a&gt;, which provided a simple and direct interface to control ASDF from the REPL. This gave me the breathing space I needed to learn how to use ASDF directly. For example, to load Drakma into a Lisp program, you call the following:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;(asdf:oos 'asdf:load-op :drakma)&lt;br /&gt;&lt;/pre&gt;I am incredibly glad I found Dr Weitz's quality packages, as my progress would've been both painful and slow otherwise. Once I had the hang of ASDF, I could use it to install other ASDF packages I downloaded.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Erlang&lt;br /&gt;&lt;/span&gt;Erlang is a monolithic language with only one distribution that I'm aware of, so I had no issues here. Again, just a case of downloading and executing a MSI installer.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Prolog&lt;/span&gt;&lt;br /&gt;Prolog has several implemenations that have compatibility issues, a la Common Lisp, but the three most widely used seems to be &lt;a href="http://www.swi-prolog.org/"&gt;SWI-Prolog&lt;/a&gt;, &lt;a href="http://www.gprolog.org/"&gt;GNU Prolog&lt;/a&gt;, and &lt;a href="http://www.clip.dia.fi.upm.es/Software/Ciao/"&gt;Ciao Prolog&lt;/a&gt;. I chose SWI because it had an extensive standard library and thorough documentation - I also prefer the LGPL over the GPL for entirely irrational reasons.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Javascript &amp; XPCOM&lt;br /&gt;&lt;/span&gt;I'd already decided to use Firefox  for this because I knew it well, I didn't need the rest of the  &lt;a href="http://www.mozilla.org/projects/seamonkey/"&gt;Seamonkey&lt;/a&gt; package (IIRC, it's a modern version of the old Mozilla Suite), and disliked the ideological reasons for the creation of &lt;a href="http://www.gnu.org/software/gnuzilla/"&gt;IceWeasel&lt;/a&gt;. The only real question was, which version to use? I went with Firefox 2.0 because it supports &lt;a href="http://developer.mozilla.org/en/docs/New_in_JavaScript_1.7"&gt;Javascript 1.7&lt;/a&gt;, which has some nifty new features, like list comprehensions, let blocks, and most importantly in my mind, destructuring bind.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Rebol&lt;/span&gt;&lt;br /&gt;The only question was - do I download&lt;a href="http://rebol.com/core-info.html"&gt; Rebol/Core&lt;/a&gt; the basic distribution, or &lt;a href="http://rebol.com/prod-view.html"&gt;Rebol/View&lt;/a&gt; which contains GUI libraries in addition to the core? In the end I went with Rebol/Core, because I wasn't going to need the GUI aspect of it, and hey, it's a 224KB download, which fascinates me - the documentation package is larger than the language!&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;IronPython&lt;/span&gt;&lt;br /&gt;There's a couple of ways to use &lt;a href="http://www.codeplex.com/Wiki/View.aspx?ProjectName=IronPython"&gt;IronPython&lt;/a&gt; - it's available as a standalone &lt;a href="http://www.codeplex.com/IronPython/Release/ProjectReleases.aspx?ReleaseId=2573"&gt;download&lt;/a&gt;, or you can install the &lt;a href="http://www.microsoft.com/downloads/details.aspx?FamilyID=51A5C65B-C020-4E08-8AC0-3EB9C06996F4&amp;displaylang=en"&gt;Visual Studio SDK&lt;/a&gt; which gives VS support for IronPython; I've chosen this course as it makes for easier editing.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;Conclusion&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;For the most part, everything was straightforward, but there's some notable exceptions.&lt;br /&gt;&lt;br /&gt;Finding the right implementation of Scheme is a complex process, there's so many of them it's not funny. Compiling Chicken took me a few days to sort, due to the VS build failing, but once I had MinGW sorted, it went fine - my Windows background feels sort of affronted when a precompiled binary isn't available, but I know that if I used *nix I'd be used to compiling from source.&lt;br /&gt;&lt;br /&gt;Getting the Common Lisp environment set up was quite painful. If it hadn't been for Edi Weitz's starter pack, I don't think I would've been able to get off the ground - a side effect of Common Lisp's multiple implementations is that documentation is somewhat fragmented. That said, I've found the legendary newbie-unfriendliness of &lt;a href="http://groups.google.co.nz/group/comp.lang.lisp/topics?hl=en"&gt;comp.lang.lisp&lt;/a&gt;'s community to be a complete myth - as long as you don't try to tell them how to 'fix' Common Lisp.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;a style="font-weight: bold;" href="http://kunosure.blogspot.com/2007/05/unscientific-comparison-getting-cookies.html"&gt;Click here for Part 3&lt;/a&gt;&lt;/span&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1724548057125197090-4033367574779839176?l=kunosure.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kunosure.blogspot.com/feeds/4033367574779839176/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1724548057125197090&amp;postID=4033367574779839176' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1724548057125197090/posts/default/4033367574779839176'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1724548057125197090/posts/default/4033367574779839176'/><link rel='alternate' type='text/html' href='http://kunosure.blogspot.com/2007/05/unscientific-comparison-first-steps.html' title='An unscientific comparison  2 - First steps'/><author><name>Cynos</name><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-1724548057125197090.post-5567998251473766868</id><published>2007-05-06T19:51:00.000-07:00</published><updated>2007-05-12T23:05:50.825-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='Rebol'/><category scheme='http://www.blogger.com/atom/ns#' term='XPCOM'/><category scheme='http://www.blogger.com/atom/ns#' term='Scheme'/><category scheme='http://www.blogger.com/atom/ns#' term='Prolog'/><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='Lisp'/><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><category scheme='http://www.blogger.com/atom/ns#' term='IronPython'/><category scheme='http://www.blogger.com/atom/ns#' term='Erlang'/><category scheme='http://www.blogger.com/atom/ns#' term='Python'/><category scheme='http://www.blogger.com/atom/ns#' term='Haskell'/><title type='text'>An unscientific comparison of programming languages</title><content type='html'>&lt;span style="font-weight: bold; font-style: italic;"&gt;Part 1 of N in a series.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;I've been playing with a bunch of new languages and paradigms recently, which is always fun, but while tutorials are helpful and all, I've always been a proponent of the deep end approach - pick a real life problem and try to resolve it.&lt;br /&gt;&lt;br /&gt;Luckily, I happen to have a problem to resolve.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;The Problem -  Scraping a web application&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The application in question consists of a series of six dynamic pages. Each page presents several options to the user as radio buttons. I need to collate both the set of options, and the context of that set  -  i.e.,  option A selected on the first page will produce a different set of options on the second page to option B, and option N on the first page, if selected, will skip to the fourth page, with a different set of options.&lt;br /&gt;&lt;br /&gt;So, I'm mapping the possible paths through the application, and the associated data. As far as scraping goes, this is more complex than I've done before, but I've already written a (very rough) prototype in Python, which produces nearly correct output that a little hand correction is needed in.&lt;br /&gt;&lt;br /&gt;In other words, it's a crude hack, and I need something that's a bit more robust, hence the rewrite.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;The Methodology&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;As I said, this is an unscientific comparison from which no conclusions can be reliably drawn. The languages are being chosen simply based on my having an interest in them, and some of them will obviously be better suited for this problem domain than other.&lt;br /&gt;&lt;br /&gt;I'm not looking for a superior language &lt;span style="font-style: italic;"&gt;per se&lt;/span&gt;, I'm just going to document my journey into places unknown. Or known very poorly.&lt;br /&gt;&lt;br /&gt;What I'm particularly interested in is:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Ease of obtaining and installing&lt;/li&gt;&lt;li&gt;Documentation&lt;/li&gt;&lt;li&gt;Breadth of any standard library&lt;/li&gt;&lt;li&gt;Availability of 3rd party modules&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;As libraries are going to play such a large part in this, I've decided to keep it as simple as possible, I'm a newbie (or near newbie) in most of these languages, so I'm going to follow this rule:&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: left;"&gt;&lt;span style="font-style: italic;"&gt;    If a given module which suits my needs exists in the standard library or is bundled with the     language, I will use it.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;&lt;/span&gt;&lt;/div&gt;&lt;br /&gt;If I can't find a necessary module in the standard library, I'll use Google to find suitable 3rd party libraries. With the above said, I'm not going to go overly silly on it. While Python's standard library contains a basic html parser (&lt;span style="font-style: italic;"&gt;very&lt;/span&gt; basic, check the &lt;a href="http://docs.python.org/lib/module-HTMLParser.html"&gt;docs&lt;/a&gt; for it), I'm not going to reinvent the wheel, I'll just use &lt;a href="http://www.crummy.com/software/BeautifulSoup/"&gt;BeautifulSoup&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;This will also help me manage the complexity... for example, there's a bunch of &lt;a href="http://mechanize.rubyforge.org/mechanize/"&gt;fantastic&lt;/a&gt; &lt;a href="http://scrubyt.org/"&gt;looking&lt;/a&gt; third party scraping frameworks for Ruby, but I could spend a month simply deciding which one to use! So, I'll use Ruby's standard library HTTP module, and &lt;a href="http://code.whytheluckystiff.net/hpricot/"&gt;Hpricot&lt;/a&gt;, which is bundled with my Ruby install.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;The languages&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.python.org/"&gt;&lt;span style="font-weight: bold;"&gt;Python&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;Python is the language I've been using the longest, it's like the comfy sweatpants you never throw out, because they fit you so well. It doesn't fill me with zealousness like it used to (A jihad on Perl and the Wallites!), but I still enjoy using it. As such, I can write a baseline app in it without the language getting in the way.&lt;br /&gt;&lt;a href="http://www.call-with-current-continuation.org/"&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Scheme&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;Attempting to read &lt;a href="http://mitpress.mit.edu/sicp/"&gt;SICP&lt;/a&gt; has instilled in me a desire to actually get a handle on Scheme. I chose Chicken Scheme because it has a coherent collation of standard/3rd party libraries should I need them. Also, Scheme that compiles to C sounded nifty.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/vcsharp/"&gt;&lt;span style="font-weight: bold;"&gt;C#&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;I've used this a bit for ASP.NET, but I've never used it in this context, and it'll provide a chance to examine bits of the .NET library that I haven't used before. Also, I needed a token "enterprisey" language. :-)&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.ruby-lang.org/"&gt;&lt;span style="font-weight: bold;"&gt;Ruby&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;As a Python user, I've been evangelised repeatedly to about the joys of Ruby. I've read the wry cartoon introductions, and flamed the zealots, so it's about time I gave it an indepth test run. Who knows, those fervent young fellows could be right...&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.haskell.org/"&gt;&lt;span style="font-weight: bold;"&gt;Haskell&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;What can I say? I read Reddit too much to not try Haskell out. I'm also hoping by the end of this I'll grok just what the hell a monad is. The type system intrigues me also.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.cs.cmu.edu/Groups/AI/html/cltl/cltl2.html"&gt;&lt;span style="font-weight: bold;"&gt;Common Lisp&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;div style="text-align: left;"&gt;SICP gave me a hankering for Scheme, Paul Graham's &lt;a href="http://www.paulgraham.com/onlisp.html"&gt;On Lisp&lt;/a&gt; did the same for Common Lisp.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.erlang.org/"&gt;&lt;span style="font-weight: bold;"&gt;Erlang&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;I've been wanting to give Erlang another spin around the block for a while now. Previously I'd written abour 2% of an MSN client in it, so I have a rough idea of how to use it. Erlang, along with Haskell, represents the 'pure' functional languages, as opposed to Scheme and Lisp. Erlang also brings the message passing concurrency paradigm to the party, which I'm going to try and use to speed up the scraping a little.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://en.wikipedia.org/wiki/Prolog"&gt;&lt;span style="font-weight: bold;"&gt;Prolog&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;Someone once told me, &lt;span style="font-style: italic;"&gt;"I always enjoyed programming in Prolog, you never quite knew how the program was going to turn out."&lt;/span&gt; So, I've got to try it at least once. It'll also be interesting to learn a bit about logical programming.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference"&gt;&lt;span style="font-weight: bold;"&gt;Javascript&lt;/span&gt;&lt;/a&gt; &lt;span style="font-weight: bold;"&gt;+ &lt;a href="http://www.xulplanet.com/references/xpcomref/"&gt;XPCOM&lt;/a&gt;&lt;/span&gt;&lt;br /&gt;A friend of mine reckons it's possible to do so, so I'll give it a shot. I'll use Firefox as the hosting engine, as I'm going to need XPCOM to write data to disk. From initial pokings, this one is going to be a lot harder than you'd think.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.rebol.com/"&gt;&lt;span style="font-weight: bold;"&gt;Rebol&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;From what little I know, Rebol was designed for this kind of problem domain. If so, I relish the chance to learn it, as it could prove to be an invaluable tool. Rebol's implementation of certain data types like dates is pretty nifty, and would be reason enough alone to have a go.&lt;br /&gt;&lt;br /&gt;&lt;a style="font-weight: bold;" href="http://www.codeplex.com/Wiki/View.aspx?ProjectName=IronPython"&gt;IronPython&lt;/a&gt;&lt;br /&gt;I've been meaning to use this for something, so here's my chance. Instead of just replicating the C# functionality with a cleaner syntax, I'm going to try to use a mixture of .NET and CPython libraries, to see how well it works.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;Conclusion&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;I'm quite looking forward to this, it should knock a few of the cobwebs out of my brain, and hopefully I'll end up with a robust webscraper at the end of it. I reiterate that the choice of languages is purely for my own satisfaction. I'd further reiterate that no language is going to "win" - this isn't one of those closeted "&lt;a href="http://kunosure.blogspot.com/2006/11/my-programming-language-mpl.html"&gt;My Programming Language&lt;/a&gt; is superior to all others!" blog posts you see from time to time, and anyone who attempts to derive such conclusions from this is misled.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;a style="font-weight: bold;" href="http://kunosure.blogspot.com/2007/05/unscientific-comparison-first-steps.html"&gt;Click here for Part 2&lt;/a&gt;&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1724548057125197090-5567998251473766868?l=kunosure.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kunosure.blogspot.com/feeds/5567998251473766868/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1724548057125197090&amp;postID=5567998251473766868' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1724548057125197090/posts/default/5567998251473766868'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1724548057125197090/posts/default/5567998251473766868'/><link rel='alternate' type='text/html' href='http://kunosure.blogspot.com/2007/05/unscientific-comparison-of-programming.html' title='An unscientific comparison of programming languages'/><author><name>Cynos</name><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-1724548057125197090.post-560453823906260478</id><published>2007-04-02T04:03:00.000-07:00</published><updated>2007-04-02T04:05:33.321-07:00</updated><title type='text'>Compare in Erlang</title><content type='html'>&lt;pre&gt;&lt;br /&gt;compare([], _)-&gt;&lt;br /&gt;    false;&lt;br /&gt;&lt;br /&gt;compare(_, [])-&gt;&lt;br /&gt;    true;    &lt;br /&gt;&lt;br /&gt;compare([_|X], [_|Y])-&gt;&lt;br /&gt;    compare(X, Y).&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/1724548057125197090-560453823906260478?l=kunosure.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kunosure.blogspot.com/feeds/560453823906260478/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1724548057125197090&amp;postID=560453823906260478' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1724548057125197090/posts/default/560453823906260478'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1724548057125197090/posts/default/560453823906260478'/><link rel='alternate' type='text/html' href='http://kunosure.blogspot.com/2007/04/compare-in-erlang.html' title='Compare in Erlang'/><author><name>Cynos</name><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-1724548057125197090.post-5195787387141413743</id><published>2007-04-01T20:09:00.000-07:00</published><updated>2007-04-01T20:47:57.294-07:00</updated><title type='text'>Static typing eh? Not that verbose eh?</title><content type='html'>&lt;pre&gt;&lt;br /&gt;using System.Collections.Generic;&lt;br /&gt;&lt;br /&gt;...&lt;br /&gt;&lt;br /&gt;public void OhFun()&lt;br /&gt;{&lt;br /&gt;   List&amp;lt;int&amp;gt; example = new List&amp;lt;int&amp;gt;();&lt;br /&gt;   example.Add(1);&lt;br /&gt;   ...&lt;br /&gt;   example.Add(10);&lt;br /&gt;   string template_string = "{0} - {1} - {2}...{9}";&lt;br /&gt;   Converter&amp;lt;int, object&amp;gt; conv = new Converter&amp;lt;int, object&amp;gt;(delegate(int in_var){return (object)in_var})&lt;br /&gt;   object[] template_args = Array.ConvertAll&amp;lt;int, object&amp;gt;(example.ToArray(), conv);&lt;br /&gt;   string final_string = String.Format(template_string, template_args);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Oh my, and &lt;a href="http://www.hacknot.info/hacknot/action/showEntry?eid=93"&gt;certain people&lt;/a&gt; have trouble with the statement that &lt;span style="font-style: italic;"&gt;"...&lt;/span&gt;&lt;em style="font-style: italic;"&gt;dynamic typing&lt;/em&gt;&lt;span style="font-style: italic;"&gt; [can] result in a reduction in code volume of 80 to 90 percent? It seems highly improbable to me."&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Strange thing is, despite the method signature specifying an object array, it's okay to pass a string array - perhaps it's being implicitly coerced into being an object array?&lt;br /&gt;&lt;br /&gt;Oh, and the dynamic variant of this code?&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;def OhFun():&lt;br /&gt;    example = []&lt;br /&gt;    example.append(1)&lt;br /&gt;    ...&lt;br /&gt;    example.append(10)&lt;br /&gt;    template_string = "%d - % d - %d...%d"&lt;br /&gt;    final_string = template_string % tuple(example)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Not 80% in my example, but nonetheless...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1724548057125197090-5195787387141413743?l=kunosure.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1724548057125197090/posts/default/5195787387141413743'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1724548057125197090/posts/default/5195787387141413743'/><link rel='alternate' type='text/html' href='http://kunosure.blogspot.com/2007/04/static-typing-eh.html' title='Static typing eh? Not that verbose eh?'/><author><name>Cynos</name><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></entry><entry><id>tag:blogger.com,1999:blog-1724548057125197090.post-5380997131312867775</id><published>2007-04-01T18:34:00.000-07:00</published><updated>2007-04-01T20:34:51.327-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='functional programming'/><category scheme='http://www.blogger.com/atom/ns#' term='Lisp'/><category scheme='http://www.blogger.com/atom/ns#' term='Python'/><title type='text'>Python doesn't feel like a very functional language</title><content type='html'>&lt;span style="font-size:100%;"&gt;I'm a big Python fan. It's what I learnt to program in, after all.&lt;br /&gt;&lt;br /&gt;Even with my recent drinking of the .NET Kool Aid I've managed to bring Python along, in the form of &lt;a href="http://blogs.msdn.com/aaronmar/archive/2006/02/16/a-bit-more-on-ironpython.aspx"&gt;IronPython integrated into Visual Studio&lt;/a&gt; - especially the REPL that I use to prototype functionality and poke new .NET objects. Sure, I could read the docs, but poking the class in question directly has always been more intuitive.&lt;br /&gt;&lt;br /&gt;But, I have to admit, sure, it may have lambda, map and reduce (at least until Python 3000), and it may have list comprehensions, but it doesn't &lt;span style="font-style: italic;"&gt;feel&lt;/span&gt; functional.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;I blame Paul Graham&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:100%;"&gt;Everytime I start reading his book, &lt;a href="http://www.paulgraham.com/onlisp.html"&gt;On Lisp&lt;/a&gt; I start getting all excited about Lisp. It's his passion, it's contagious. But I have this problem in that I have trouble grokking Lisp. That is, I'm not at the level that I can read it and understand it.&lt;br /&gt;&lt;br /&gt;So, my usual approach when I hit code I can't quite figure out is I try to transliterate it into Python. Once I've successfully done so, I'll type the Lisp variant into SLIME - once I know why the function was written the way it was, rewriting it in Lisp gives me the &lt;span style="font-style: italic;"&gt;feel&lt;/span&gt; of it. And a lot of Lisp feels elegant as I type it. I can see why this stuff is habit forming.&lt;br /&gt;&lt;br /&gt;So rewriting into Python is a great way of breaking down what a function does... I'm not sure what I'll do when he starts getting into macros.&lt;br /&gt;&lt;br /&gt;But doing so makes Python feel very inelegant. I can feel that I'm doing things with Python that run counter to the grain of the language. It looks inelegant too.&lt;br /&gt;&lt;br /&gt;For example - Graham gives a function to find if list X is longer than list Y.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;(defun compare (x y)&lt;br /&gt;  (and (consp x)      &lt;br /&gt;   (or (null y)      &lt;br /&gt;       (compare (cdr x) (cdr y)))))&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The literal translation into Python is&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;def compare(x, y):&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if x != [] and (y == [] or compare(x[1:], y[1:])):&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return True&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return False&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;It can be simplified a tad to&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;def compare(x, y):&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if x and (not y or compare(x[1:], y[1:])):&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return True&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return False&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;But it's still missing that sensation of flow that gets called "Pythonicness", which is a clear sign that you're using Python wrong.&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-size:100%;"&gt;I know I've used the word "feel" repeatedly, but that's what it comes down to. The Lisp isn't immediately accessible by reading it, neither is the Python. But when you're typing them out, the Lisp correlates seamlessly with the functional thought process, the Python feels like you're cramming on shoes that don't quite fit. I've read about this sensation before - admittedly, at the time I thought the &lt;a href="http://www.defmacro.org/ramblings/lisp-ducati.html"&gt;Lisp - Ducati&lt;/a&gt; analogy was a tad pretentious, but I see where he's coming from.&lt;br /&gt;&lt;br /&gt;Anyway, this doesn't mean I'm becoming a Lisp addict, but it does mean that a former Python zealot is having to admit to himself that there's something his favourite language doesn't do overly well.&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-size:100%;"&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;Conclusion&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:100%;"&gt;There's been a lot of grumbling about the removal of functional aspects in Py3K. The removal of map, list, filter and reduce is no biggy, as the list comprehension cheerfully stolen from Haskell (syntax and all) fulfills the same need. But it's the slated removal of the crippled lambda that's raised the most hackles. There's been many proposals for special syntax to allow multi-lined lambdas, but none have been accepted by the BDFL.&lt;br /&gt;&lt;br /&gt;At the end of the day, Python really isn't a very capable functional language, and I don't think that multi-lined lambda would fix that. It's the syntax, it's the philosophy, and it's the &lt;span style="font-style: italic;"&gt;feel&lt;/span&gt; of Python that make it a fantastic dynamic imperative language and a half-hearted functional one.&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1724548057125197090-5380997131312867775?l=kunosure.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kunosure.blogspot.com/feeds/5380997131312867775/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1724548057125197090&amp;postID=5380997131312867775' title='13 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1724548057125197090/posts/default/5380997131312867775'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1724548057125197090/posts/default/5380997131312867775'/><link rel='alternate' type='text/html' href='http://kunosure.blogspot.com/2007/04/python-doesnt-feel-like-very-functional.html' title='Python doesn&apos;t feel like a very functional language'/><author><name>Cynos</name><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-1724548057125197090.post-3277033527635259812</id><published>2006-11-15T19:43:00.000-08:00</published><updated>2007-01-09T12:43:23.891-08:00</updated><title type='text'>Opera, Firefox, and IE7 - they all suck/rock</title><content type='html'>I feel uniquely situated to comment on the recent bout of browser releases, as I use Opera 9 at home for my daily browsing, Firefox 2 for development, and at work I use Firefox 2 for most of my browsing, and IE7 out of "lazy coder" necessity - as in I have to use certain very expensive J2EE websites that can't populate drop down boxes unless you're using the IE DOM.&lt;br /&gt;&lt;br /&gt;I don't have a particular loyalty to any one browser. I do derive much enjoyment from the Fx fans versus Opera fans. So, my scientifically derived opinion on the recent crop of browsers?&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;They all suck and rock. Except for IE7.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;That just sucks full stop. Let me break it down for you. My biggest bugbear tends to be resource usage. Yeah, Moore's Law etc. But when performance gradually degrades as usage continues over time, I get annoyed. (Don't try and tell me there's no memory leaks in Firefox, by the way)&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;Opera sucks...&lt;/span&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Worst. Javascript. Error. Console. Ever.&lt;/li&gt;&lt;li&gt;Reconfiguring UI involves *.ini files in weird places.&lt;/li&gt;&lt;li&gt;Strange behaviour on some websites (A favourite &lt;a href="http://www.gpforums.co.nz/"&gt;haunt of mine&lt;/a&gt; will flash three times on loading. Can't figure out why.&lt;/li&gt;&lt;li&gt;It doesn't have an equivalent to FX extensions (Yes, I know, most of the time you don't need them, but the capability would be nice.)&lt;/li&gt;&lt;li&gt;Can get RAM heavy after long periods of browsing (the 100MB mark)&lt;/li&gt;&lt;li&gt;Can have issues with the Shockwave plugin&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;Opera rocks...&lt;/span&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Render time. You do notice this when reverting to other browsers.&lt;/li&gt;&lt;li&gt;Response time. The UI "feels" more responsive.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Most of what Fx users install extensions for is built-in already.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Can do some mighty interesting things with those *.ini files.&lt;/li&gt;&lt;li&gt;More lightweight than Firefox or IE7&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;Firefox sucks...&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;font-size:85%;" &gt;Please note that (especially in regards to my complaints of memory) I have tweaked my Fx 2 install to minimise these - I even started a &lt;a href="http://hwiki.digitalsouth.net.nz/net_appns/fx2config"&gt;wiki page&lt;/a&gt; to catalog the tweaks&lt;/span&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Resource hungry - my average browsing session with 15 tabs open will sit at the ~250MB mark normally.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Slow render time. You &lt;span style="font-style: italic;"&gt;do&lt;/span&gt; notice this after using Opera.&lt;/li&gt;&lt;li&gt;UI feels a little tardy at time&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Tabs can become unresponsive when another tab is loading - seems like a threading issue&lt;/li&gt;&lt;li&gt;&lt;span style="font-family:courier new;"&gt;about:config&lt;/span&gt;/Mozilla wiki - if I'm going to need your wiki to figure out how to fix FX 2 to work with my proxy, then please host it on a server that responds in milliseconds rather than minutes.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Assumptions that my system font will be the default size, leading to dialog sizing issues. Having to install custom chrome to fix this stinks. Thunderbird has the same issue. &lt;/li&gt;&lt;li&gt;Random crashes a bit too often.&lt;/li&gt;&lt;li&gt;"Missing plugin" ribbon has to be turned off via about:config&lt;br /&gt;&lt;/li&gt;&lt;li&gt;XPCOM is very, very, ugly&lt;/li&gt;&lt;li&gt;Firefox fanboys need to &lt;a href="http://xkcd.com/c198.html"&gt;get a life&lt;/a&gt;.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;Firefox rocks...&lt;/span&gt;&lt;ul&gt;&lt;li&gt;Good basic development support (moderately useful console, DOM inspector)&lt;br /&gt;&lt;/li&gt;&lt;li&gt;The concept of plugins&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Plugins like Firebug, Colorzilla etc. that make Fx2 the dev's best friend&lt;/li&gt;&lt;li&gt;Some beautiful skins&lt;/li&gt;&lt;li&gt;No rendering issues that I've seen&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;Internet Explorer 7 sucks...&lt;/span&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;100% CPU usage, &lt;span style="font-style: italic;"&gt;every single time it renders a page&lt;/span&gt;&lt;/li&gt;&lt;li&gt;Nearly as bad as Firefox 2 when it comes to RAM usage&lt;/li&gt;&lt;li&gt;Ugly UI&lt;/li&gt;&lt;li&gt;Stupidly uncustomisable UI&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Security warnings that assume I'm stupid&lt;/li&gt;&lt;li&gt;Very slow renders&lt;/li&gt;&lt;li&gt;Unresponsive feel to UI&lt;/li&gt;&lt;li&gt;Moving the menu bar back to the normal position involves a registry hack&lt;/li&gt;&lt;li&gt;Turning off security warnings involves a group policy edit&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;&lt;br /&gt;Internet Explorer 7 rocks...&lt;/span&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;...um... IE6 is now obsolete?&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;Conclusion&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;Opera 9&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Feels the lightest when in use and tends to have the smallest footprint on system resources. I prefer this for my usual browsing.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;Firefox 2&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Still a bit heavy, and feels sluggish after Opera. However, with a few plugins, is the developer's best friend for Javascript work.&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;br /&gt;Internet Explorer 7&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Feels like a half-assed attempt to copy Fx2, and assumes at every level that you are an idiot. I'm not kidding.&lt;br /&gt;&lt;br /&gt;Modifying certain security settings to make IE7 more secure (for instance, disallowing programmatic access to the Clipboard) will result in a ribbon coming up saying "Warning! Your settings aren't secure!". Being lectured by a piece of software that's wrong is just irritating It shows the IE guys obviously assumed that any change from a default setting was bad - whether by policy or laziness, I don't know.&lt;br /&gt;&lt;br /&gt;Assuming stupidity is my guess as to why you can no longer drag and drop the UI - no doubt many a newbie managed to drag and drop their back/forward buttons and address bar out of existence, so it gets turned off for all of us.&lt;br /&gt;&lt;br /&gt;So, Opera for browsing, Firefox 2 for development, and IE7 for lazy IE-only coders.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1724548057125197090-3277033527635259812?l=kunosure.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kunosure.blogspot.com/feeds/3277033527635259812/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1724548057125197090&amp;postID=3277033527635259812' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1724548057125197090/posts/default/3277033527635259812'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1724548057125197090/posts/default/3277033527635259812'/><link rel='alternate' type='text/html' href='http://kunosure.blogspot.com/2006/11/modern-day-browsers-annoy-crap-out-of.html' title='Opera, Firefox, and IE7 - they all suck/rock'/><author><name>Cynos</name><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-1724548057125197090.post-1444056975245095247</id><published>2006-11-02T12:27:00.000-08:00</published><updated>2006-11-02T13:06:18.925-08:00</updated><title type='text'>My Programming Language (MPL)</title><content type='html'>Not quite on a par with the One True Language (OTL) syndrome but still repellent is the "My Programming Language".&lt;br /&gt;&lt;br /&gt;Seems to occur in people who've used a particular language for a long time, and it manifests as an inability to accept criticism of the MPL. If someone's criticizing it, then they obviously don't know what they're talking about.&lt;br /&gt;&lt;br /&gt;MPL differs from OTL in that it's not based on faith and fervour but more a sense of intellectual superiority and skill based on that language - and so insulting the MPL by proxy insults the intellect of the MPLer.&lt;br /&gt;&lt;br /&gt;Case in point is &lt;a href="http://scienceblogs.com/goodmath/2006/11/the_c_is_efficient_language_fa.php"&gt;this article&lt;/a&gt;, wherein the author is responding to an article which states that C/C++ is good for numeric processing - from the article, he appears to know the problem domain, but that doesn't stop the MPLers:&lt;br /&gt;&lt;p&gt;&lt;blockquote&gt;BTW, I've seen a number of these comparisions where an expert in one language does an implementation in several languages and, lo and behold, discovers that their favorite language wins out. It's all the same computer underneath, so if you aren't getting fast code in one language (that's sufficiently expressive) IT'S YOUR FAULT (whether because you aren't a good enough programmer in that language, don't know your compiler well enough, or aren't using the right compiler (the old Programming Language Shootout used GCC, which often gets its butt kicked by the Intel compiler on Intel machines)) not the language's.&lt;/blockquote&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;...Except in this case, the author's favourite language (C++) &lt;span style="font-style: italic;"&gt;lost&lt;/span&gt; when he compared it to other languages in this problem domain. I tend to trust the author's statement that Fortran is used for number crunching over C because someone's making and selling updated Fortran compilers. &lt;span style="font-style: italic;"&gt;Selling.&lt;/span&gt;&lt;/p&gt;&lt;p&gt;So, if you're a MPLer, don't be. Different problem domains have different solutions; you wouldn't write a telephone exchange in Ruby, and you wouldn't write a web framework in Fortran. I hope.&lt;br /&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1724548057125197090-1444056975245095247?l=kunosure.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kunosure.blogspot.com/feeds/1444056975245095247/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1724548057125197090&amp;postID=1444056975245095247' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1724548057125197090/posts/default/1444056975245095247'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1724548057125197090/posts/default/1444056975245095247'/><link rel='alternate' type='text/html' href='http://kunosure.blogspot.com/2006/11/my-programming-language-mpl.html' title='My Programming Language (MPL)'/><author><name>Cynos</name><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-1724548057125197090.post-1072327594316152104</id><published>2006-09-25T02:51:00.000-07:00</published><updated>2006-09-25T03:02:26.339-07:00</updated><title type='text'>Windows user meets Emacs II</title><content type='html'>Well. Today was surprisingly fruitful.&lt;br /&gt;&lt;br /&gt;My goals were:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-size:100%;"&gt;&lt;span style="font-size:100%;"&gt;Change Emac's default interface font if possible&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size:100%;"&gt;&lt;span style="font-size:100%;"&gt;Setup syntax highlighting for Erlang&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size:100%;"&gt;&lt;span style="font-size:100%;"&gt;Investigate indentation for Python&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;The first was easily done, so let's move on.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;Setting up Erlang in Emacs&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;After some googling, I found  &lt;a href="http://erlang.org/doc/doc-5.5.1/lib/tools-2.5.1/doc/html/erlang_mode_chapter.html"&gt;this&lt;/a&gt;. Turns out the people who distributed Erlang were way ahead of me. Erlang came with two files necessary to make Emacs and Erlang play nicely.&lt;br /&gt;&lt;br /&gt;I did, however, have to break my Windows metaphor... I created a &lt;span style="font-weight: bold;"&gt;.emacs &lt;/span&gt;file, and then inserted the following text in it:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;(setq load-path (cons  "C:/Program Files/erl&lt;ver&gt;/lib/tools-&lt;toolsver&gt;/emacs"&lt;br /&gt;     load-path))&lt;br /&gt;(setq erlang-root-dir "C:/Program Files/erl&lt;ver&gt;")&lt;br /&gt;(setq exec-path (cons "C:/Program Files/erl&lt;ver&gt;/bin" exec-path))&lt;br /&gt;(require 'erlang-start)&lt;br /&gt;&lt;/ver&gt;&lt;/ver&gt;&lt;/toolsver&gt;&lt;/ver&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;That kind of stuff tends to worry/annoy me. I know Lisp when I'm seeing it, and I've heard all about Emacs Lisp, but yeah. Unix comes crashing in.&lt;br /&gt;&lt;br /&gt;But, once that I was done, hey presto, I was away.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;That's all for now&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;I didn't get a chance to investigate the Python indentation, but seeing as how Erlang can do it, I may need to steal some Lisp from Erlang and insert it into Python. I also need to bind shift + tab. I'm finding killing/yanking to be quite different to copy/pasting. Killing is quite powerful so I'll have to be careful with that. Learning the keys will take awhile, but it's been a lot less painful than I imagined.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1724548057125197090-1072327594316152104?l=kunosure.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kunosure.blogspot.com/feeds/1072327594316152104/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1724548057125197090&amp;postID=1072327594316152104' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1724548057125197090/posts/default/1072327594316152104'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1724548057125197090/posts/default/1072327594316152104'/><link rel='alternate' type='text/html' href='http://kunosure.blogspot.com/2006/09/windows-user-meets-emacs-ii.html' title='Windows user meets Emacs II'/><author><name>Cynos</name><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-1724548057125197090.post-9163643965153749879</id><published>2006-09-24T04:17:00.000-07:00</published><updated>2006-09-24T04:20:22.182-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Erlang'/><category scheme='http://www.blogger.com/atom/ns#' term='Python'/><category scheme='http://www.blogger.com/atom/ns#' term='Emacs'/><title type='text'>Windows user meets Emacs</title><content type='html'>My mouse's right button died. Never realise how much you use it until you lose it. I've rebound it to one of those pretty flashing-but-useless buttons on the left hand side, but it's awkward - makes coding painful.&lt;br /&gt;&lt;br /&gt;So, in an effort to kill two birds with one stone, I'm going to try to learn how to use Emacs. I may regret it. (The other bird is write code without pain until next pay day.)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;&lt;span style="font-size:130%;"&gt;I'm like Bill Murray in Japan.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:100%;"&gt;I must admit that I've only had about six months of *nix experience. Enough to learn that Gnome is more performance intensive than Windows XP, that XFCE is a nice lightweight alternative, that the way Debian manages console fonts is lacking compared to other distros and I've learnt the rudiments of the filesystem, although run levels and the associated files still confuse me.&lt;br /&gt;&lt;br /&gt;I also learnt some basic Vim, enough to SSH into a *nix server and edit an Apache config file in it without worrying too much about breaking stuff.&lt;br /&gt;&lt;br /&gt;But I never touched Emacs in *nix. I did use it as part of &lt;a href="http://common-lisp.net/project/lispbox/"&gt;Lisp in a Box&lt;/a&gt; but only in the interactive Common Lisp mode, it was too confusing to try and edit with.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;Foreseeable obstacles&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size:100%;"&gt;&lt;br /&gt;The culture and language is going to be the largest hurdle, I think. Buffers. Meta keys. Mini-buffers... I'm okay with esoteric key sequences once I know what they're doing, but Emacs&lt;br /&gt;seems like nothing else I've used.&lt;br /&gt;&lt;br /&gt;Richard Stallman's cleverness is another. It may just be that Emacs is too difficult for me to grok. I sometimes wonder if *nix text editors were designed as some sort of initiation rite into a secret *nix brotherhood. If you could create a new file and save it, you were in. You got a swish badge and an impressive title if you could turn on &lt;a href="http://en.wikipedia.org/wiki/Code_folding"&gt;code folding.&lt;/a&gt;  We'll find it.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;The parameters&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-size:100%;"&gt;I'm not going to change OSes. I can't be bothered installing another OS for the sake of a text editor. So Win32 it is.&lt;/span&gt;&lt;/li&gt;&lt;br /&gt;&lt;br /&gt;&lt;li&gt;&lt;span style="font-size:100%;"&gt;As I'm on Windows, I'm not going to compile anything. It's a pain in the butt for someone who doesn't know much about *nix development environments to replicate - the pain I experienced when trying to compile Python extensions using MinGW was horrendous.&lt;/span&gt;&lt;/li&gt;&lt;br /&gt;&lt;br /&gt;&lt;li&gt;&lt;span style="font-size:100%;"&gt;All I want to do is write code.&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;So my targets for tonight:&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;Install Emacs&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;Create a new file and save it&lt;br /&gt;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;Open a Python file and an Erlang file and explore code highlighting&lt;br /&gt;&lt;/span&gt;&lt;/li&gt;&lt;/ol&gt;&lt;span style="font-weight: bold;"&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;Step 1: Install Emacs&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:100%;"&gt;I feed Google"learning emacs on windows" - hoping to find newbie related materials. 4th result is http://www.emacswiki.org which looks hopeful - despite the trash talking I give Wikipedia, I do like wikis for this sort of stuff  - I've learnt to love them through learning wxPython etc.&lt;br /&gt;&lt;br /&gt;http:///www.emacswiki.org is good. Under &lt;span style="font-style: italic;"&gt;Downloading and Installing&lt;/span&gt;, I find a page on Win32 ports in particular. After a few mouseclicks, I find myself at the homepage of &lt;a href="http://ourcomments.org/Emacs/EmacsW32.html"&gt;EmacsW32&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Hmmm, do I want the&lt;a href="http://ourcomments.org/Emacs/EmacsW32.html#unpatched"&gt; patched or unpatched version?&lt;/a&gt; From the looks of it, I'll want the functionality of the patched version, with the caveat that it could be brittle.&lt;br /&gt;&lt;br /&gt;I download the install file, a nice typical Windows installer, and execute it. I have to stop and think about the file extensions questions, and when it asks me if I want to associate the "Open" verb for XML with Emacs, I'm guessing that saying yes means Emacs will open them for editing, not try to run them.&lt;br /&gt;&lt;br /&gt;A console window pops up while EmacsW32 edits some Lisp files, and then I'm away.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;Step 2: Create a new file and save it&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;I could use the two huge buttons on the toolbar, but I want to learn the key sequences. Luckily, the key sequences are listed in the drop down menus besides the functions.&lt;br /&gt;&lt;br /&gt;I hit &lt;span style="font-style: italic;"&gt;ctrl + x, ctrl + f &lt;/span&gt;and enter my new file's name. I enter some text and pres &lt;span style="font-style: italic;"&gt;ctrl + x, ctrl + w&lt;/span&gt;. That was reasonably straight forward. I'm quite pleased with how Emacs handles directory listings.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Step 3: Python and Erlang&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Emacs recognises the Python immediately and turns on syntax highlighting immediately. I'm a bit disappointed that when I press enter in an indented block that my cursor isn't moved to the same indent - but that may just be an option I have to change.&lt;br /&gt;&lt;br /&gt;Emacs doesn't seem to recognise the Erlang file at all, so perhaps I need to enable syntax highlighting for that, or Emacs may not have it installed by default. I can't figure out how to check the syntax settings via the menus, so it's time for the Emacs tutorial - well, I'll do that tomorrow.&lt;br /&gt;&lt;br /&gt;Tomorrow's mission:&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-size:100%;"&gt;&lt;span style="font-size:100%;"&gt;Change Emac's default interface font if possible&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size:100%;"&gt;&lt;span style="font-size:100%;"&gt;Setup syntax highlighting for Erlang&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size:100%;"&gt;&lt;span style="font-size:100%;"&gt;Investigate indentation for Python&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;span style="font-size:100%;"&gt;&lt;span style="font-size:100%;"&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:100%;"&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-size:100%;"&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-size:100%;"&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1724548057125197090-9163643965153749879?l=kunosure.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kunosure.blogspot.com/feeds/9163643965153749879/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1724548057125197090&amp;postID=9163643965153749879' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1724548057125197090/posts/default/9163643965153749879'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1724548057125197090/posts/default/9163643965153749879'/><link rel='alternate' type='text/html' href='http://kunosure.blogspot.com/2006/09/windows-user-meets-emacs.html' title='Windows user meets Emacs'/><author><name>Cynos</name><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-1724548057125197090.post-4729095530485221434</id><published>2006-09-21T16:03:00.000-07:00</published><updated>2006-09-21T18:05:47.560-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='Python'/><title type='text'>Ruby and Python - there's no fight</title><content type='html'>Apparently, it's a &lt;a href="http://t-a-w.blogspot.com/2006/09/fight-to-death-between-ruby-and-python.html"&gt;fight to the death between the two languages&lt;/a&gt;, based on the ecological principle of "competitive exclusion" which states that two species can't share the same ecological niche without specialization or one becoming extinct.&lt;br /&gt;&lt;br /&gt;I have problems with this analogy because it doesn't account for the evidence, and I also have issues with the above gentleman's assertions that Ruby is more powerful.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;&lt;span style="font-size:130%;"&gt;Remember when everyone stopped using PHP?&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;/span&gt;&lt;/strong&gt;&lt;br /&gt;Hah, I wish. But here's a list of languages/frameworks that share the same ecological niche in the coding world, but yet are still present and still being used.&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;ASP/ASP.NET/PHP/&lt;em&gt;your templating language here&lt;/em&gt;&lt;insert&gt;&lt;/li&gt;&lt;li&gt;Javascript/VBScript&lt;/li&gt;&lt;li&gt;Java/C#&lt;/li&gt;&lt;li&gt;VB.NET/VB6&lt;/li&gt;&lt;li&gt;Ruby/Python/Perl&lt;/li&gt;&lt;li&gt;Haskell/OCAML&lt;/li&gt;&lt;/ul&gt;I'm sure there's thousands of other examples that I've missed. If the principle of competitive exclusion applied in the programming world, there'd be one templating framework, one client-side browser scripting language, one functional language, etc. etc.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;strong&gt;Programming languages are not subject to natural selection&lt;/strong&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Natural selection is ruthless. Humans, not so. The fact that there are still COBOL programmes running will attest to this. There will always be plenty of room within a "niche" for various alternatives. Aside from dubious, highly unscientific assertions based on book sales via O'Reilly, there's no evidence that Ruby is usurping Python's userbase. (Re: those book sales - Ruby's community should take that as a sign that they need to improve their online documentation.)&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;strong&gt;Ruby users be hatas, yo... why?&lt;/strong&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;/span&gt;&lt;br /&gt;Funnily enough, when I see statements like "It's a fight to the death" it's invariably from a Ruby user.&lt;br /&gt;&lt;br /&gt;I don't see it from Python users because Python is out of the One True Language (OTL) phase, so the userbase isn't as fervent these days, we're a bit more tolerant, and more willing to filch good ideas.&lt;br /&gt;&lt;br /&gt;I came into Python just as the OTL phase was ending (in those days, it was fight to the death between Perl and Python), so I've seen the community mature over time, and the fanatics either settle down or move on. (Guess where they moved onto...)&lt;br /&gt;&lt;br /&gt;So, a question for any Ruby users who read this - you seem to be of the opinion that Ruby needs to kill Python. Why? Python didn't need to kill Perl.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Now, moving onto address &lt;a href="http://t-a-w.blogspot.com/2006/09/fight-to-death-between-ruby-and-python.html"&gt;Tomasz Węgrzanowski&lt;/a&gt;'s points. Incidentally, anyone else find his usage of a cat picture highly ironic given the nature of the post? Unintentional, I'm sure.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;strong&gt;Power and popularity&lt;/strong&gt;&lt;/span&gt;&lt;br /&gt;&lt;strong&gt;&lt;span style="font-size:130%;"&gt;&lt;/span&gt;&lt;/strong&gt;&lt;br /&gt;Quotes from taw are given in italics. He states that&lt;br /&gt;&lt;br /&gt;&lt;em&gt;right now - Ruby is a bit more powerful, Python is a bit more popular&lt;/em&gt;&lt;br /&gt;&lt;br /&gt;and he defines power and popularity as:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Power (expressiveness, performance etc.)&lt;/li&gt;&lt;li&gt;Popularity (which results in more libraries, better tools, fewer bugs etc.)&lt;/li&gt;&lt;/ul&gt;&lt;em&gt;&lt;strong&gt;So if you want Python to win:&lt;/strong&gt;&lt;/em&gt;&lt;br /&gt;&lt;br /&gt;&lt;em&gt;Reduce the gap in power - make Python support blocks, get rid of explicit self and get better support for metaprogramming. If Python did it a few years ago, nobody would have heard of Ruby. If you don't like blocks, metaprogramming and implicit self, you don't have to use them - simply consider them a price to pay for making Python the next big thing. If it gets them today, it is still very likely to win.&lt;/em&gt;&lt;br /&gt;&lt;em&gt;&lt;/em&gt;&lt;br /&gt;I must admit that I fail to see how the usage of &lt;strong&gt;self&lt;/strong&gt; means Python isn't as "powerful". It fits with the Python philosophy of &lt;em&gt;explicit is better than implicit&lt;/em&gt; - I can't see how it impacts performance or expressiveness in any way. Blocks would be nice, but metaprogramming? If metaprogramming is why I need a language, I'm going to use a Lisp dialect.&lt;br /&gt;&lt;br /&gt;&lt;em&gt;Reverse gap in power - can Python express certain things a lot better than Ruby ? Write useful programs and libraries that would be much more difficult without this power and popularize them. Attack the enemy where it is strongest.&lt;/em&gt;&lt;br /&gt;&lt;em&gt;&lt;/em&gt;&lt;br /&gt;I don't understand this point, so I can't really answer it.&lt;br /&gt;&lt;br /&gt;&lt;em&gt;Make the most of greater popularity - work on useful things that are very useful but hard to reproduce with smaller user base - like Psyco and stable ports to JVM and .NET&lt;/em&gt;&lt;br /&gt;&lt;em&gt;&lt;/em&gt;&lt;br /&gt;Okay. Do Jython and IronPython 1.0 qualify as stable ports to JVM and .NET? IronPython even managed to retain compatibility with most of the CPython standard library.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;&lt;em&gt;And if you want Ruby to win:&lt;/em&gt;&lt;/strong&gt;&lt;br /&gt;&lt;strong&gt;&lt;em&gt;&lt;/em&gt;&lt;/strong&gt;&lt;br /&gt;&lt;em&gt;Increase power advantage - take powerful features from Lisps, Smalltalk, Erlang, Haskell or whatever, and integrate them with Ruby - making different paradigms work together is one of the greatest strengths of Ruby, so make use of it. Make metaprogramming and DSLs easier by writing metalibraries and tutorials.&lt;/em&gt;&lt;br /&gt;&lt;em&gt;&lt;/em&gt;&lt;br /&gt;I'd add a cautionary note to this, there's an old saying about being a jack of all trades, but a master of none. Ruby should focus on being a good Ruby, and not a half-decent Lisp, a quarter decent Erlang and a two-thirds okay Smalltalk.&lt;br /&gt;&lt;br /&gt;I'd still reiterate that if you need to metaprogramming and DSLs that you're more than likely going to be using Lisp. L# has just been released, which I find interesting, as it has access to the .NET libraries.&lt;br /&gt;&lt;br /&gt;But anyway, before Ruby goes stealing stuff from every other language, give it threading and unicode first. Get the basics right.&lt;br /&gt;&lt;br /&gt;&lt;em&gt;Make the most of greater power - Ruby was able to get the momentum with Ruby on Rails, which would be very difficult to replicate in other languages. Ruby makes writing powerful embedded DSLs very easy, and powerful embedded DSLs are a potentially huge and pretty much unfilled niche. Take it and use it as a leverage to get more popularity.&lt;/em&gt;&lt;br /&gt;&lt;em&gt;&lt;/em&gt;&lt;br /&gt;Ruby on Rails is hard to replicate? Sorry, Django, Turbogears, Pylon, Zope, Cherrypy etc. you guys are too hard to use... erm... RoR is easy to replicate.&lt;br /&gt;&lt;br /&gt;DSLs are a hard way to sell your language. They haven't worked for Lisp yet. Before you can sell Ruby based on DSLs, you need to tell people why they need DSLs.&lt;br /&gt;&lt;br /&gt;&lt;em&gt;Minimize effects of lesser popularity - if Python has a good library for something, simply recode it to Ruby and call it version 1.0. The languages are so similar that you should be able to do it in no time. You can get it more Ruby-like (with blocks etc.) later.&lt;/em&gt;&lt;br /&gt;To be honest, I wouldn't recommend this. For example - Ruby's&lt;em&gt; imap&lt;/em&gt; library is, in my opinion, better than Python's&lt;em&gt; imaplib&lt;/em&gt; &lt;span style="font-size:85%;"&gt;(apologies to ESR who wrote the part that annoys me the most, but an IMAP library that requires me to use syntax from the IMAP4rev2 RFC is failing)&lt;/span&gt;&lt;span style="font-size:100%;"&gt;, so replicating some of Python's libraries would be a mistake - at least until Python 3000's general revision, tidy up and improvement of the standard library has occurred. &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;em&gt;There are some things in which current implementation of Python is simply better - Ruby 2 is trying to fix many of those (you cannot have Ruby Psyco without &lt;/em&gt;&lt;a href="http://en.wikipedia.org/wiki/YARV"&gt;&lt;em&gt;YARV&lt;/em&gt;&lt;/a&gt;&lt;em&gt;). If you can - help with Ruby 2.&lt;/em&gt;&lt;br /&gt;&lt;em&gt;&lt;/em&gt;&lt;br /&gt;Yes. The priorities of the Ruby community should be - threading, unicode, speed, documentation. These are what Ruby needs right now. I'll keep an eye out.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1724548057125197090-4729095530485221434?l=kunosure.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kunosure.blogspot.com/feeds/4729095530485221434/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1724548057125197090&amp;postID=4729095530485221434' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1724548057125197090/posts/default/4729095530485221434'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1724548057125197090/posts/default/4729095530485221434'/><link rel='alternate' type='text/html' href='http://kunosure.blogspot.com/2006/09/ruby-and-python-theres-no-fight.html' title='Ruby and Python - there&apos;s no fight'/><author><name>Cynos</name><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-1724548057125197090.post-2435052131457609635</id><published>2006-09-20T15:48:00.000-07:00</published><updated>2006-09-20T15:56:45.690-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Python'/><title type='text'>Python and white space - biggest strawman ever</title><content type='html'>Someone commented on an earlier post of mine that he wouldn't use Python because of the syntactically important whitespace.&lt;br /&gt;&lt;br /&gt;Bah, this is the lamest reason. Tell me that you want full closures, tell me that you hate explicit &lt;em&gt;self,&lt;/em&gt; tell me that you don't like Guido, tell me that Ruby on Rails is far superior to Django/Turbogears/Zope etc. - but don't pick on the whitespace, it's a lazy argument.&lt;br /&gt;&lt;br /&gt;Why?&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;&lt;span style="font-size:130%;"&gt;Ever used XML?&lt;/span&gt; &lt;/strong&gt;&lt;br /&gt;&lt;strong&gt;&lt;/strong&gt;&lt;br /&gt;&lt;strong&gt;Yup, by default, that's got syntactically important whitespace too.&lt;/strong&gt;&lt;br /&gt;&lt;strong&gt;&lt;/strong&gt;&lt;br /&gt;If you don't believe me, you need to &lt;a href="http://www.oracle.com/technology/pub/articles/wang-whitespace.html"&gt;read this.&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;(Anyway, how hard is it to press tab? If you indent code in a sane manner anyway, the only difference between Python and every other language is a lack of braces/keywords.)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1724548057125197090-2435052131457609635?l=kunosure.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kunosure.blogspot.com/feeds/2435052131457609635/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1724548057125197090&amp;postID=2435052131457609635' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1724548057125197090/posts/default/2435052131457609635'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1724548057125197090/posts/default/2435052131457609635'/><link rel='alternate' type='text/html' href='http://kunosure.blogspot.com/2006/09/python-and-white-space-biggest-strawman.html' title='Python and white space - biggest strawman ever'/><author><name>Cynos</name><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-1724548057125197090.post-2144914059856679937</id><published>2006-09-19T18:18:00.000-07:00</published><updated>2006-09-19T18:35:15.003-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='Python'/><title type='text'>Ruby vs. Python - why no-one should care</title><content type='html'>&lt;strong&gt;&lt;span style="font-size:130%;"&gt;BECAUSE THEY FILL THE SAME DAMNED NICHE.&lt;/span&gt;&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;I hate it when I see people trying to start flame wars over this. It's dumb. Ever noticed how &lt;a href="http://www.c2.com/cgi/wiki?UsingPythonDontNeedRuby"&gt;Python users&lt;/a&gt; and &lt;a href="http://www.c2.com/cgi/wiki?UsingRubyDontNeedPython"&gt;Ruby users&lt;/a&gt; are, as a general rule, not really interested in moving to the other language?&lt;br /&gt;&lt;br /&gt;It's because they fulfill the exact same need.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Object orientated? &lt;strong&gt;Check&lt;/strong&gt;&lt;/li&gt;&lt;li&gt;High level?&lt;strong&gt; Check&lt;/strong&gt;&lt;/li&gt;&lt;li&gt;Support functional programming?&lt;strong&gt; Check&lt;/strong&gt;&lt;/li&gt;&lt;li&gt;Garbage collected?&lt;strong&gt; Check&lt;/strong&gt;&lt;/li&gt;&lt;li&gt;Dynamically typed? &lt;strong&gt;Check&lt;/strong&gt;&lt;/li&gt;&lt;li&gt;Expressive? &lt;strong&gt;Check&lt;/strong&gt;&lt;/li&gt;&lt;li&gt;Fast to develop in? &lt;strong&gt;Check&lt;/strong&gt;&lt;/li&gt;&lt;li&gt;Small, usable standard libraries? &lt;strong&gt;Check&lt;/strong&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Yeah, Ruby has closures, you can do the same stuff in multiple ways, it has Ruby on Rails, it has code blocks, and it has symbols, and Python's faster, does threading , unicode, has more web frameworks than keywords, has more third party libraries and the standard library is better documented, but honestly, this stuff only matters when you're deciding which one to invest your time in; that is, before you've learnt either.&lt;/p&gt;&lt;p&gt;Once you've made that time investment, there's no additional gain to be made from learning the other for the sake of it.&lt;br /&gt;&lt;br /&gt;If you're a Java programmer, whom Ruby's community seems to be targetting, I'm sure that Ruby is pretty damned impressive. Any dynamically typed language has got to feel like heaven after Java. Ex-Java programmers seem to like Python too.&lt;/p&gt;&lt;p&gt;Once I've got Python or Ruby down pat, I don't need the other. &lt;/p&gt;&lt;p&gt;Let's run over it again&lt;/p&gt;&lt;ul&gt;&lt;li&gt;They fill the same niche&lt;/li&gt;&lt;li&gt;They have the same functionality&lt;/li&gt;&lt;li&gt;They have similar communities &lt;span style="font-size:85%;"&gt;&lt;em&gt;(Usually helpful, occasionally frosty, always passionate)&lt;/em&gt;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;They've both been the Next Big Thing &lt;span style="font-size:85%;"&gt;&lt;em&gt;(Yeah, I'm using past tense for both, sorry Ruby dervishes)&lt;/em&gt;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;They're &lt;a href="http://www.c2.com/cgi/wiki?PythonAndRubyAreConverging"&gt;converging&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;So, &lt;strong&gt;STOP EVANGELISING. &lt;/strong&gt;I'm looking at fervid Pythonistas and rabid Ruby lovers both. It's inane, and you're wasting your time, and ours.&lt;/p&gt;&lt;p&gt;&lt;em&gt;&lt;span style="font-size:85%;"&gt;&lt;strong&gt;Footnote:&lt;/strong&gt; I'm generalising, so please don't tell me about your conversion either which way - what I'm saying holds true for the greater majority of both communities, there will always be exceptions.&lt;/span&gt;&lt;/em&gt; &lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1724548057125197090-2144914059856679937?l=kunosure.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kunosure.blogspot.com/feeds/2144914059856679937/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1724548057125197090&amp;postID=2144914059856679937' title='26 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1724548057125197090/posts/default/2144914059856679937'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1724548057125197090/posts/default/2144914059856679937'/><link rel='alternate' type='text/html' href='http://kunosure.blogspot.com/2006/09/ruby-vs-python-why-no-one-should-care.html' title='Ruby vs. Python - why no-one should care'/><author><name>Cynos</name><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>26</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1724548057125197090.post-6863976810131442759</id><published>2006-09-19T14:22:00.000-07:00</published><updated>2006-09-19T14:23:47.996-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='blog'/><title type='text'>Hmmm, beta-y goodness</title><content type='html'>Oh dear, Blogger seems to be inserting tags at random through my earlier post. Weird.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1724548057125197090-6863976810131442759?l=kunosure.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kunosure.blogspot.com/feeds/6863976810131442759/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1724548057125197090&amp;postID=6863976810131442759' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1724548057125197090/posts/default/6863976810131442759'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1724548057125197090/posts/default/6863976810131442759'/><link rel='alternate' type='text/html' href='http://kunosure.blogspot.com/2006/09/hmmm-beta-y-goodness.html' title='Hmmm, beta-y goodness'/><author><name>Cynos</name><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-1724548057125197090.post-1438814140384781328</id><published>2006-09-18T18:28:00.000-07:00</published><updated>2006-09-18T22:03:25.364-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Erlang'/><title type='text'>My firstish impressions of Erlang</title><content type='html'>Having just read &lt;a href="http://t-a-w.blogspot.com/2006/09/my-first-impressions-of-erlang.html"&gt;this blog entry&lt;/a&gt; about someone else's first experiences with Erlang galvanises me to write this.&lt;br /&gt;&lt;br /&gt;I'm going to do it "good, bad, ugly" but as everyone likes the critical stuff more than the gushy stuff, I'll do it backwards.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;strong&gt;The ugly&lt;/strong&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Strings. I bet you're surprised I started with that.&lt;br /&gt;&lt;br /&gt;I'll start by noting that Erlang wasn't designed to twiddle strings, so you've got to keep that in mind when moaning about this - it's like complaining that Perl sucks for writing large fault tolerant concurrent telephony systems.&lt;br /&gt;&lt;br /&gt;However, as there's a push in certain circles to spread the Erlang word into wider usage, now would be a good time for whoever maintains Erlang to consider revising string handling, because Erlang will never enter wider acceptance without the ability to handle a wider variety of tasks.&lt;br /&gt;&lt;br /&gt;So, what's bad about strings?&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Spa&lt;/strong&gt;&lt;strong&gt;ce&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;Each character is represented as an integer ASCII code. So, on my 32 bit system, that's 4 bytes for the character. A string is a linked list of characters, so that's another 4 bytes for each pointer, so we're looking at 8 bytes per character. Eep. (There's an upside to this, however, which I'll cover later.) - if you were handling a whole bunch of strings, you could hit memory issues, theoretically.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Speed&lt;br /&gt;&lt;/strong&gt;&lt;br /&gt;I don't know how broad this is, but from my tinkerings, string concatenation can be very slow if you do it wrong, because it's a linked list. I ran into this trying to write a recursive function to replicate Python's join method.&lt;br /&gt;&lt;br /&gt;I was using an accumulator, to which various strings were being appended. Problem is, each time that something was appended to the accumulator, Erlang had to follow the pointers to find the end of it... which leads to O(n*n) execution time... the trick it would seem in Erlang is to build strings backwards. If I were going to joib the list ["The", "cat", "sat", "on", "the", "mat"] with spaces, using my approach would've looked like this&lt;br /&gt;&lt;br /&gt;"The "&lt;br /&gt;"The cat "&lt;br /&gt;"The cat sat "&lt;br /&gt;"The cat sat on "&lt;br /&gt;"The cat sat on the "&lt;br /&gt;"The cat sat on the mat "&lt;br /&gt;&lt;br /&gt;Each iteration, Erlang would have to traverse the string to find the end. Whereas if I built it backwards, each list item would only be traversed once.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Unicode&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;Every programming language needs to support UTF-8 as standard. I'm not going to beat up Erlang too hard for this considering that Python and Ruby can't quite manage this either... at least until Python 3000.&lt;br /&gt;&lt;br /&gt;I will comment that Erlang's usage of integers at least leaves the room for UTF-8 to be implemented.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;String functions and regexes&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;Argh, no join? Also, strip functions that strip single characters at a time are not overly groovy.&lt;br /&gt;&lt;br /&gt;As for the regex module... well, it's nice to have some functionality, (Although it was funny place to stick the split function) but in a post-Perl world, I feel like a caveman if I can't retrieve a group from a regex like &lt;em&gt;"&lt;a&gt;(.*?)&lt;/a&gt;"&lt;/em&gt; but instead have to use a combination of calls to regexp:match() and some adding and subtracting string indexes.&lt;br /&gt;&lt;br /&gt;That's about it on the strings, for now. I'll cover some nice things about them later.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;strong&gt;The bad&lt;/strong&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Syntax&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;I spent a lot of time wrestling with the syntax, mainly around the end of line delimiters and which to use where. Do you really need three of 'em? Now that I'm used to it and I've discovered &lt;a href="http://erlide.sourceforge.net/"&gt;Erlide&lt;/a&gt;, a plugin for Eclipse, my worries have disappeared, but the syntax is a hurdle to getting into Erlang.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Documentation&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;There is heaps of documentation available for Erlang... when you find it. I was bitterly amused when I looked up the built-in functions in the reference manual and saw "For a complete list of built-in functions, refer to&lt;em&gt; erlang(3)&lt;/em&gt;."&lt;br /&gt;&lt;br /&gt;Being told to refer to man pages on Windows is a bitter moment. Luckily, I found out about &lt;a href="http://www.die.net/"&gt;http://www.die.net/&lt;/a&gt;. I found the documentation for the tcp sockets easily enough (&lt;em&gt;gen_tcp&lt;/em&gt;) but it didn't have any information about the socket options, or where to find them. The socket options are listed in the documentation for the&lt;em&gt; inet&lt;/em&gt; module, but you do wonder why a link from gen_tcp to the relevant section of inet wasn't included.&lt;br /&gt;&lt;br /&gt;Also, there are some useful functions that are undocumented, &lt;em&gt;xmlerl:to_utf8&lt;/em&gt; being one I've noticed recently.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;The standard library&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;If you need to work with an URI, in Python you use &lt;em&gt;urllib&lt;/em&gt;. In Ruby you use &lt;em&gt;uri&lt;/em&gt;. Both libraries come in the standard library.&lt;br /&gt;&lt;br /&gt;Erlang has.... Erlang has... Well, Erlang has &lt;em&gt;yaws_api&lt;/em&gt;. Except it's not part of the standard library, it's part of Yaws, which is a webserver which you have to download separately.&lt;br /&gt;&lt;br /&gt;Yeah, I know, telephony etc, but as I said, if you want to push a language to a wider audience, you'll need to cater to a wider range of tasks.These days, you'll inevitably end up manipulating URIs for some reason or another. Making &lt;em&gt;yaws_api&lt;/em&gt; part of the standard library couldn't hurt at all.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Hey?! How did I end up in Visual Basic?&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;What's the index of a first element of a list? 0 right? Unless you use Visual Basic *snicker*... or Erlang.&lt;br /&gt;&lt;br /&gt;In Erlang's defense, considering it has the [First_element ¦ Rest_of_list] capability &lt;em&gt;a la &lt;/em&gt;Lisp's &lt;em&gt;car&lt;/em&gt; and &lt;em&gt;cdr&lt;/em&gt;, you don't need to use a numeric reference all that often, but still...&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#ff0000;"&gt;(Let me just clarify that this is a really tiny, insignificant issue, dear Reddit readers, honestly, I can live with it, see above re Erlang's variant on&lt;em&gt; car&lt;/em&gt; meaning that you'll rarely need to use list indexes, but it does contribute ever so slightly to culture shock.)&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;strong&gt;The good&lt;/strong&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;Okay, the boring bit now. ;) Despite my moans and gripes, Erlang is still pretty neat.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Pattern matching&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;Every language needs this! I am not kidding. This is a feature I often found myself wishing for when working in Python, without realising what it was called. For example, my (terribly inefficient) join function looked like this:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;join([], Delimiter, Acc) -&gt;&lt;br /&gt;    Acc;&lt;br /&gt;&lt;br /&gt;join([H¦T], Delimiter) -&gt;&lt;br /&gt;    join(T, Delimiter, [H]);&lt;br /&gt;&lt;br /&gt;join([H¦T], Delimiter, Acc) -&gt;&lt;br /&gt;    join(T, Delimiter, Acc ++ Delimiter ++ H).&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Basically, when I call the join function, Erlang will check to see which of the above definitions the arguments I pass matches, and then call that. &lt;/p&gt;&lt;br /&gt;How I'd have to do this without pattern matching would be something like this -&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;join(TheList, Delimiter, Acc) -&gt;&lt;br /&gt;if length(TheList) == 0 -&gt;&lt;br /&gt;    Acc;&lt;br /&gt;else -&gt;&lt;br /&gt;    H = lists:nth(1, TheList),&lt;br /&gt;    T = lists:nthtail(1, TheList),&lt;br /&gt;    if Acc == 0 -&gt;&lt;br /&gt;        join(T, Delimiter, [H]);&lt;br /&gt;    else -&gt;&lt;br /&gt;        join(T, Delimiter, Acc ++ Delimiter ++ H)&lt;br /&gt;    end,&lt;br /&gt;end.&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Note the lovely demonstration of the multiple line end delimiters ;)&lt;br /&gt;But as you can see, pattern matching rocks the kasbah. You can also pattern match in case statements. This is one useful language feature. &lt;/p&gt;&lt;p&gt;&lt;strong&gt;Asynchrous message passing&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;I'm only just delving into this, but this and fault tolerance is where the strength of Erlang lies.&lt;/p&gt;&lt;p&gt;The best part from my limited dabbling is that sockets send asynchrous messages to processes.&lt;/p&gt;&lt;p&gt;What that means is that if the socket receives data, it sends the data in a message to the process that owns it - thus the process doesn't need to keep polling the socket and there's no messy "avoid a blocking socket" shenanigans. In other words, what Twisted Python tries to add to Python is built into Erlang from the get go, event orientated networking.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;It's beautiful. Your socket handling process merely has to handle three kinds of message (one for data, one for the socket being remotely closed, and one for other errors) and that's it. An asynchrous non-blocking socket. No threading, no Queue objects, no Timeout exceptions, no blocking sockets. It's how it should be.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;I'm well aware of the obvious faults of Erlang, but the obvious features of it are attractive enough to deal with the bad and the ugly&lt;strong&gt;.&lt;/strong&gt; As I keep playing with it, I'll learn more and develop a rounder opinion of it. But for now, I am intrigued. Also, FP languages are always good fun - thinking recursively does hurt my brain though.&lt;/p&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;strong&gt;Now, to the fisking&lt;/strong&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:100%;"&gt;Now for the &lt;/span&gt;&lt;a href="http://t-a-w.blogspot.com/2006/09/my-first-impressions-of-erlang.html"&gt;&lt;span style="font-size:100%;"&gt;article that inspired this one&lt;/span&gt;&lt;/a&gt;&lt;span style="font-size:100%;"&gt;... bold and italics are the original, my comments follow.&lt;br /&gt;&lt;/span&gt;&lt;strong&gt;&lt;br /&gt;&lt;span style="font-size:100%;"&gt;Lack of basic Unix decency&lt;/span&gt;&lt;/strong&gt;&lt;span style="font-size:100%;"&gt; - &lt;i&gt;no man page for erl or erlc (at least in the Ubuntu package), they do not accept --help, one cannot exit by ^D. These are very basic things. If they're broken, people are likely to leave.&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;I'm a bit confused by this. I found the man pages easy, and I'm using Windows.&lt;br /&gt;I don't know how Linux distros work, but is it expected that they ship with manuals for obscure&lt;br /&gt;programming languages preinstalled? Talk about bloatware...&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;strong&gt;&lt;br /&gt;&lt;span style="font-size:100%;"&gt;Interpreter is terribly underpowered&lt;/span&gt;&lt;/strong&gt;&lt;span style="font-size:100%;"&gt; - &lt;/span&gt;&lt;span style="font-size:100%;"&gt;&lt;i&gt;in most languages you can write pretty much any code in an interpreter. In Erlang you cannot even define functions there. Of course there is no online help.&lt;br /&gt;&lt;br /&gt;&lt;/i&gt;As an avid Python user myself, I completely agree. Compared to Python's interactive interpreter, Erlang's interpreter is underpowered. But then, last time I checked, interactive interpreters weren't exactly the industry standard. Try finding one for Perl. I tried a Ruby one once, but it broke when I pressed enter three times in a row. They may have fixed it now though. The inability to define functions is about as annoying as not being able to define things in DrScheme without restarting the interpreter.&lt;br /&gt;&lt;br /&gt;Myself, I have a test.erl file that I define functions in, like DrScheme really. As I'm using &lt;/span&gt;&lt;a href="http://erlide.sourceforge.net/"&gt;&lt;span style="font-size:100%;"&gt;Erlide&lt;/span&gt;&lt;/a&gt;&lt;/span&gt;&lt;/span&gt;, an Eclipse plugin, I have my editor and my interpreter right there. I then define the new function, and recompile. Which brings me to the chap's next point...&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;span style="FONT-WEIGHT: bold"&gt;You actually have to compile your code&lt;/span&gt;, &lt;span style="FONT-STYLE: italic;font-size:85%;" &gt;by hand, before you can use it - if you wrote a hello_world.erl, you have to compile it using erlc, then run erl, and call hello_world:whatever. If you made a mistake, you need to exit the main loop (by halt()., not ^D, to waste more of your time), correct the mistake, recompile, and start again.&lt;/span&gt;&lt;/p&gt;&lt;p&gt;Yes, you compile the code. But exiting the interpreter to do it? Funnily enough, there's a function called &lt;a href="http://www.erlang.org/doc/doc-5.5.1/lib/stdlib-1.14.1/doc/html/index.html"&gt;c()&lt;/a&gt; that compiles it for you...&lt;span style="font-size:100%;"&gt;...this complaint convinces me that the gentleman posting has not bothered to read the &lt;/span&gt;&lt;a href="http://www.erlang.org/doc/doc-5.5.1/doc/getting_started/seq_prog.html#2.1"&gt;&lt;span style="font-size:100%;"&gt;Getting Started with Erlang Guide&lt;/span&gt;&lt;/a&gt; in the HTML documentation, because it mentions it about 6 code samples in.&lt;/p&gt;&lt;p&gt;That's classic foot-in-mouth... reading the F manual is a good thing to do; I learnt that from harsh experience.&lt;/p&gt;&lt;p&gt;&lt;span style="FONT-WEIGHT: bold"&gt;Don't Repeat Yourself ? Nah&lt;/span&gt; &lt;span style="font-size:100%;"&gt;- &lt;span style="FONT-STYLE: italic;font-size:85%;" &gt;In Erlang you have to repeat yourself a lot. In every file you need to write module name and list of all exported functions. And when you use them you have to prefix them by module name anyway. So even though foo:bar() simply has to be function bar in module foo, you have to explicitly list in on the export list in foo.erl anyway.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-size:100%;"&gt;Oh come on, it's &lt;span style="FONT-WEIGHT: bold"&gt;two lines. &lt;/span&gt;That aside, his complaint about having to explicitly export functions outside the module is weird. In the OO world, this is pretty darned commonplace, you know, all those &lt;span style="FONT-STYLE: italic"&gt;private&lt;/span&gt; and &lt;span style="FONT-STYLE: italic"&gt;public&lt;/span&gt; keywords that litter the place. Even in Python where the motto is &lt;span style="FONT-STYLE: italic"&gt;"We're all consenting adults"&lt;/span&gt; and the language isn't designed to enforce encapsulation, there's a naming convention to indicate objects and variables that are deemed private by the developer and such, don't rely on them. So, Taw doesn't like encapsulation, a central tenet of OO? Keep that in mind for his next complaint...&lt;/span&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;span style="FONT-WEIGHT: bold"&gt;It is not even marginally object-oriented. &lt;/span&gt;&lt;span style="FONT-STYLE: italic;font-size:85%;" &gt;I'm not talking about having to hack object-orientation on top of it - it's just that basic object do not know what they are.&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;Ah, wait, no! OO is now good. But Taw has made a fatal mistake. He's mistaken a pure functional language for Ruby! If Ruby has closures, then it must be functional right? &lt;a href="http://www.c2.com/cgi/wiki?ReferentialTransparency"&gt;Referential transparency? &lt;/a&gt;What's that? When you're using a functional style in languages like Lisp that support FP and OO, you tend not to use objects, it seems to make things harder. A pure functional language does fine without objects, but Taw misses them. &lt;/p&gt;&lt;p&gt;&lt;span style="FONT-WEIGHT: bold"&gt;&lt;br /&gt;Lists of numbers cannot tell themselves apart from strings&lt;/span&gt; &lt;span style="font-size:85%;"&gt;&lt;span style="FONT-STYLE: italic"&gt;and so on. Writing "Hello, world\n" out will actually output [72,101,108,108,111,44,32,119,111,114,108,100,10].&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-size:100%;"&gt;Taw has stumbled on the implementation of strings in Erlang without realising it. The one valid point he could've had, and he fumbles. See his next complaint for when the ball hits the ground.&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="FONT-WEIGHT: bold"&gt;&lt;br /&gt;String support is horrible&lt;/span&gt; - &lt;span style="font-size:85%;"&gt;&lt;span style="FONT-STYLE: italic"&gt;As I said, strings do not exist as first-class objects, they are emulated by strings. So no Unicode. No regular expressions. No high-level string functions. We're back to C.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-size:100%;"&gt;His gripe about a lack of objects in a functional language and a weird muttering about emulation we can ignore.&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="FONT-WEIGHT: bold"&gt;Unicode. &lt;/span&gt;&lt;span style="FONT-STYLE: italic"&gt;xmlerl:to_utf8&lt;/span&gt; and &lt;span style="FONT-STYLE: italic"&gt;xmlerl:from_utf8&lt;/span&gt; - they're not documented, but they're there.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="FONT-WEIGHT: bold"&gt;No regular expressions?&lt;/span&gt; Don't tell the regexp module it doesn't exist...&lt;/li&gt;&lt;li&gt;&lt;span style="FONT-WEIGHT: bold"&gt;No high level string functions? &lt;/span&gt;Don't tell the string module either...&lt;/li&gt;&lt;li&gt;&lt;span style="FONT-WEIGHT: bold"&gt;We're back to C&lt;/span&gt; Actually in C strings would be smaller in memory and faster, but I digress. :p&lt;/li&gt;&lt;/ul&gt;Strings in Erlang seem to suck if you've come from anything other than C, no-one denies that, but you've got to criticise real faults, not "I didn't read the manual" stuff.&lt;br /&gt;&lt;br /&gt;&lt;span style="FONT-WEIGHT: bold"&gt;Not Invented Here Syndrome&lt;/span&gt; - &lt;span style="font-size:85%;"&gt;&lt;span style="FONT-STYLE: italic"&gt;Erlang tries it very hard to be different than everything else. Syntax is different (somewhat Prolog-like), Unix conventions are disregarded, standard data types (strings, arrays and hash tables) are not provided, even io:format uses its own format strings instead of following printf. You cannot simply take a look at a few examples and start writing useful programs like with Ruby, Python or even Java. Not following conventions wastes everyone's time.&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:100%;"&gt;This one I'm going to break down again.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-size:100%;"&gt;&lt;/span&gt;&lt;span style="font-size:100%;"&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="FONT-WEIGHT: bold;font-size:100%;" &gt;Syntax. &lt;/span&gt;&lt;span style="font-size:100%;"&gt;Erlang was implemented in Prolog, hence why it looks like Prolog.&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="FONT-WEIGHT: bold;font-size:100%;" &gt;Unix conventions. &lt;/span&gt;&lt;span style="font-size:100%;"&gt;I guess he means Ctrl ^ D. Trivia, but hey, I'm on Windows, so what do I know, it could be a life or death thing in *nix. Although my experiences with *nix GUIs would suggest that *nix isn't big on conventions anyway.&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="FONT-WEIGHT: bold;font-size:100%;" &gt;Standard data types. &lt;/span&gt;&lt;span style="font-size:100%;"&gt;There are strings, there are arrays, and there's even a hashtable you can use if you really want. Just because Erlang calls them different things and does them differently, doesn't mean they don't exist! How do you find the lack of hashtables in Python? (Dictionary? Wassat?)&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="FONT-WEIGHT: bold;font-size:100%;" &gt;io:format doesn't copy printf. &lt;/span&gt;&lt;span style="font-size:100%;"&gt;Which is true, it copies &lt;span style="FONT-STYLE: italic"&gt;format&lt;/span&gt; from Lisp...&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;&lt;/span&gt;&lt;li&gt;&lt;span style="FONT-WEIGHT: bold;font-size:100%;" &gt;It's not Ruby, Python or Java. &lt;/span&gt;&lt;span style="font-size:100%;"&gt;Well spotted! His complaint about the examples confirms he hasn't read the &lt;a href="http://www.erlang.org/doc/doc-5.5.1/doc/getting_started/seq_prog.html#2.1"&gt;Getting Started Guide&lt;/a&gt; as I started writing my concurrent MSN client within half an hour of installing. Sure, it was terrible code, but I was writing it. I'd like to claim I'm a better coder, but I'd be talking rubbish.&lt;span style="FONT-STYLE: italic"&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="FONT-WEIGHT: bold;font-size:100%;" &gt;Not following conventions wastes everyone's time. &lt;/span&gt;&lt;span style="font-size:100%;"&gt;So does not reading documentation and expecting every language to be Ruby, hmmm? &lt;/span&gt;&lt;span style="FONT-WEIGHT: bold;font-size:100%;" &gt;&lt;br /&gt;&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;em&gt;&lt;/em&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1724548057125197090-1438814140384781328?l=kunosure.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kunosure.blogspot.com/feeds/1438814140384781328/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1724548057125197090&amp;postID=1438814140384781328' title='20 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1724548057125197090/posts/default/1438814140384781328'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1724548057125197090/posts/default/1438814140384781328'/><link rel='alternate' type='text/html' href='http://kunosure.blogspot.com/2006/09/my-firstish-impressions-of-erlang.html' title='My firstish impressions of Erlang'/><author><name>Cynos</name><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>20</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1724548057125197090.post-8081576887243851424</id><published>2006-09-14T20:37:00.000-07:00</published><updated>2006-09-14T22:03:47.959-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Plone'/><category scheme='http://www.blogger.com/atom/ns#' term='open source'/><category scheme='http://www.blogger.com/atom/ns#' term='OSS'/><category scheme='http://www.blogger.com/atom/ns#' term='government'/><title type='text'>OSS - Issues</title><content type='html'>My employer recently rolled out &lt;a href="http://www.plone.org/"&gt;Plone&lt;/a&gt; as our new CMS - you can see the results here - &lt;a href="http://www.companies.govt.nz/"&gt;www.companies.govt.nz&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;(Note that the transactional sections are still J2EE I think, I'm not entirely sure as to the technology being used there.)&lt;br /&gt;&lt;br /&gt;In the short term it means that information can be updated very quickly, so if any information is erroneous or causing confusion for our clients the turnaround time to fix it is now measured in hours instead of days. This is brilliant; if information provisioned is inaccurate, it makes your entire organistion look incompetent.&lt;br /&gt;&lt;br /&gt;Also, it just looks &lt;em&gt;good&lt;/em&gt;. It even has rounded corners - how Web 2.0 is that?&lt;br /&gt;&lt;br /&gt;I've been inputting data into a internal instance we're using for our knowledge store; and occasionally assisting in tweaking of the templates and some Python scripting. And wow, just wow - the capabilities. I love the versioning when editing data, and working with Python is, I think, every Python nut's dream - and it's actually quite powerful, even with the restricted execution environment.&lt;br /&gt;&lt;br /&gt;Long term, I think our adoption of Plone is going to help establish the viability (or lack thereof) of OSS for use in the public sector in New Zealand. Let me explain that although I use a lot of OSS, I'm not a zealot. I'm a cheapskate, mainly. But I think the public sector needs OSS to be a viable option - it would save the taxpayer a lot of money.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;&lt;span style="font-size:130%;"&gt;Caution: Tautology follows&lt;/span&gt;&lt;/strong&gt;&lt;br /&gt;&lt;strong&gt;&lt;/strong&gt;&lt;br /&gt;Government departments are very conservative when it comes to technology, for understandable reasons - they're highly publicly accountable for failures, especially when those failures involve large amounts of personal information about citizens that the government department has collected in its privileged role.&lt;br /&gt;&lt;br /&gt;In this regard, I think that the culture of OSS as commonly perceived is a liability to uptake by technologically conservative organisations, and as such OSS is fighting an uphill battle to even be considered by the non-techies who make the actual decisions.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;&lt;span style="font-size:130%;"&gt;"You need to install the latest unstable SVN branch"&lt;/span&gt;&lt;/strong&gt;&lt;br /&gt;&lt;strong&gt;&lt;/strong&gt;&lt;br /&gt;OSS development is pretty jungle like. Useful projects can die horrible deaths unexpectedly, the roar of competing bull developers can be heard as a project forks/schisms (Emacs/XEmacs), and sometimes you can fall into the swamp of poor documentation and , and occasionally you have to hack wearily away at the undergrowth just to get where you wanted to be.&lt;br /&gt;&lt;br /&gt;In short "unstable branch" is a pretty good way to describe a common misconception of OSS - well, the "unstable" bit. This, however, can be dealt with - if you promote the fact that OSS projects can be stable. I think there's a tendency to emphasise bleeding edge over "doesn't crash and easy to get running".&lt;br /&gt;&lt;br /&gt;If I'm a newbie to your new technology, something reliable is going to leave a better impression than your latest alpha release.&lt;br /&gt;&lt;br /&gt;Your latest alpha may have scorching hot features that are revolutionary but if I have to download several patches from SVN,  install a beta module for Apache and a third party hack for that module merely to get it working with my Apache install, I'm not going to be impressed. (It's what killed my interest in Turbogears - Django doesn't let you swap out templating languages like Turbogears, but it doesn't require that you do terrible things to Apache to get it to work. That's a big bonus.)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;&lt;span style="font-size:130%;"&gt;"The High One said you need to install the latest unstable SVN branch"&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/strong&gt;Okay, so a glib passing swipe at the Prophets of RMS, and the Church of Latter Day ESR (post-dotcom, natch) - but the zealotry of OSS uber alles doesn't help their cause at all. It scares people away. Advocates of open source have trouble being taken seriously. Want to know why? Write a blog entry criticising OSS Sacred Cow X (Firefox, Wikipedia, etc. etc. ad nauseum.) Make sure you only include valid criticisms. Watch as the rabid fanatics denying that their Cow is anything but divine outnumber the rational advocates 100:1. Watch as the rational advocates cringe at the hyperbole and personal attacks of the zealots.&lt;br /&gt;&lt;br /&gt;Watch as the zealots help shape a wrong conception of the OSS community.&lt;br /&gt;&lt;br /&gt;You see, instability and dervishes are by and far not true for the majority. But they are perceived by your average "weened on Windows" manager as representing all of OSS. And guess who gets to make the decision on what to use.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;&lt;span style="font-size:130%;"&gt;So what to do?&lt;/span&gt;&lt;/strong&gt;&lt;br /&gt;&lt;strong&gt;&lt;/strong&gt;&lt;br /&gt;&lt;strong&gt;Stop with the fanaticism. Really. OSS won't cure cancer. All you're doing is scaring people off. Thanks.&lt;/strong&gt;&lt;br /&gt;&lt;strong&gt;&lt;/strong&gt;&lt;br /&gt;Seriously, take Plone as an example. It's rock solid, it's a proven technology, it's used worldwide by various organisations, it has wonderfully powerful features, it's &lt;em&gt;&lt;strong&gt;FREE&lt;/strong&gt;&lt;/em&gt;, and still it is seen as a huge risk.&lt;br /&gt;&lt;br /&gt;Sure, Microsoft got in there with their FUD and muddied the waters, but instead of calmly proving Microsoft wrong, the Church of OSS has been churning furiously, making it worse.&lt;br /&gt;&lt;br /&gt;I'll put it this way - when you see Rev Phelps on TV, are you judging his argument based on the actual merits of it, or are you judging his argument based on the fact that he seems to be a total madman who's trying to suppress his own latent homosexuality?&lt;br /&gt;&lt;br /&gt;Every time you type "Micro$oft" or "Winblows", you're doing a Phelps, and Microsoft is winning.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;&lt;span style="font-size:100%;"&gt;Emphasise stable releases&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: normal;"&gt;I'm not picking on &lt;/span&gt;&lt;a style="font-weight: normal;" href="http://www.turbogears.org/"&gt;Turbogears&lt;/a&gt;&lt;span style="font-weight: normal;"&gt;, honest, I quite like the concept it embodies but it is a really good example - go to their website, what's the available version available with one click on their front page? It's 1.0b1 - the last time I checked, it was an alpha version. Want to find the latest non-beta or alpha release? Click on Download in the top menu, now scroll down. About half way down, between TurboCheetah and TurboJson you'll find Turbogears 0.9.5 - I just hope you know what to do with a Python Egg.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: normal;"&gt;There was some fabulous features added between Turbogears 0.9.5 and 1.0, so I can understand their excitement over 1.0b1. But, how's it going for the users? Check the &lt;a href="http://groups.google.com/group/turbogears?lnk=srg"&gt;Google Group &lt;/a&gt;- how many "Upgrade to 1.0b1 broke my install" and "1.0b1 not working" posts can you see? Okay, so it may be unfair to highlight such a new project, but there are people using Turbogears in production - I tried to run a production site on an older version, and then gave up in disgust when one upgrade broke my whole install. Upgrades should not break installs lightly.&lt;br /&gt;&lt;br /&gt;Compare though, Python's download page - very first link is the production version, 2.4.3. Python 2.5 has some pretty damn cool features, such as pysqlite which is a Python interface to SQLite, becoming part of the standard library - having contributed occasionally to pysqlite in a docs and bugs way, I can't wait to play with Python 2.5.&lt;br /&gt;&lt;br /&gt;But, where's the 2.5 RC2 download link? After all the links to the current production (that is, stable) version of Python.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/strong&gt;&lt;span style="font-size:130%;"&gt;&lt;strong&gt;Finis&lt;/strong&gt;&lt;/span&gt;&lt;br /&gt;&lt;strong&gt;&lt;/strong&gt;&lt;br /&gt;Of course, I'm generalizing like mad. There's other issues too, like UI designed by programmers not designers, poor documentation, and occasionally hostile user communities, but they're easily fixable. But, I feel, as a pragmatic OSS user, that a combination of the "Ooh shiny whizbang" and "Raraghhhah Bill Gates wants to own your soul" is detrimental.&lt;br /&gt;&lt;br /&gt;If it was technically savvy and experienced people who made the final decisions, we'd be okay - but it very rarely is in large organisations. OSS needs to put on a suit.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;&lt;/strong&gt;&lt;br /&gt;&lt;strong&gt;&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;&lt;/strong&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1724548057125197090-8081576887243851424?l=kunosure.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kunosure.blogspot.com/feeds/8081576887243851424/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1724548057125197090&amp;postID=8081576887243851424' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1724548057125197090/posts/default/8081576887243851424'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1724548057125197090/posts/default/8081576887243851424'/><link rel='alternate' type='text/html' href='http://kunosure.blogspot.com/2006/09/biggest-problem-are-fans.html' title='OSS - Issues'/><author><name>Cynos</name><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-1724548057125197090.post-5271003975048505629</id><published>2006-09-12T16:22:00.000-07:00</published><updated>2006-09-12T16:24:19.054-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='blog'/><category scheme='http://www.blogger.com/atom/ns#' term='CSS'/><title type='text'>On blogging</title><content type='html'>I've moved from Wordpress to here for the sole reason that I can edit the CSS, thus making the addition of basic syntax highlighted code to my posts a lot easier - I miss the pretty Wordpress templates, but I was able to hack around with the template here until I produced something satisfactory.&lt;br /&gt;&lt;br /&gt;Incidentally, beta.blogger.com &gt; blogger.com.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1724548057125197090-5271003975048505629?l=kunosure.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kunosure.blogspot.com/feeds/5271003975048505629/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1724548057125197090&amp;postID=5271003975048505629' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1724548057125197090/posts/default/5271003975048505629'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1724548057125197090/posts/default/5271003975048505629'/><link rel='alternate' type='text/html' href='http://kunosure.blogspot.com/2006/09/on-blogging.html' title='On blogging'/><author><name>Cynos</name><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></feed>
