<?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-6577188874632264829</id><updated>2011-08-04T08:52:53.151+10:00</updated><category term='install'/><category term='ruby'/><category term='growl'/><category term='hibernate'/><category term='scala'/><category term='commandline'/><category term='fp'/><category term='whyfp'/><category term='example'/><category term='scm'/><category term='scoodi'/><category term='bash'/><category term='upgrade'/><category term='types'/><category term='split'/><category term='multipart'/><category term='find'/><category term='git'/><category term='ie6'/><category term='browser'/><category term='upload'/><category term='rails'/><category term='haskell'/><category term='html'/><category term='mac'/><category term='macports'/><category term='mercurial'/><category term='vcs'/><category term='update'/><category term='subversion'/><title type='text'>My Hacking Journal</title><subtitle type='html'>A journal to record my notes and ideas related to software development and computing</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://kristian-domagala.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6577188874632264829/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://kristian-domagala.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Kristian Domagala</name><uri>http://www.blogger.com/profile/01334114225292145389</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>15</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-6577188874632264829.post-1587021992712432900</id><published>2010-02-14T15:14:00.004+10:00</published><updated>2010-02-14T15:39:12.696+10:00</updated><title type='text'>Comment on previous post</title><content type='html'>I received a comment from a past work colleague of mine via Buzz in response to &lt;a href="http://kristian-domagala.blogspot.com/2009/04/using-type-system-for-discoverability.html"&gt;my previous post&lt;/a&gt; about my experiences with dynamically typed languages. Unfortunately, what I wanted to write didn't fit in the blog comments, hence the new post:&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;Murray Spork - So if I comment here I guess the comment only appears in Buzz - or does buzz know how to post this to your blog?&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;Looks like it's not that smart yet...&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;My thoughts:&lt;br /&gt;&lt;br /&gt;1. I think you are correct in identifying the main problem of dynamic languages - what has been call "contract obfuscation"&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;I think it's more the fact that it is not a system that allows contracts to be automatically checked.&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;2. Test driven dev is essential with dynamic languages (well - I would say it is essential even when using static languages ;-). I feel your pain regarding maintaining the existing Rails app - but if they had better test coverage that would have gone a long way to solve that problem&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;It depends how coverage is determined. As I mentioned in the previous post, this particular code base had over 98% coverage, but it didn't take into account multiple code paths on a single line.&lt;br /&gt;&lt;br /&gt;It's also not as effective as it's made out to be. Imagine I had some sort of &lt;code&gt;address&lt;/code&gt; property on a &lt;code&gt;User&lt;/code&gt;. I write unit tests around the &lt;code&gt;User&lt;/code&gt; class based on the internal meaning of the property. Then, I write tests around all code that accesses the &lt;code&gt;address&lt;/code&gt; property. I do that using a mock framework:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;  mockUser.expects(address).andReturns("1 Park Road")&lt;br /&gt;  proxy = new Proxy(mockUser)&lt;br /&gt;  assertThat(proxy.address).equals("1 Park Road")&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Now, three months down the track, we find out that a user can have multiple addresses, and we store them as a map (&lt;code&gt;:residential -&gt; "1 Park Road", :postal -&gt; "PO Box 132"&lt;/code&gt;), under a new property called &lt;code&gt;addresses&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;So the new programmer on the team goes in and updates the &lt;code&gt;User&lt;/code&gt; class (or should I say, updates the tests around the &lt;code&gt;User&lt;/code&gt; class first, then updates the &lt;code&gt;User&lt;/code&gt;) so that it uses the new "&lt;code&gt;addresses&lt;/code&gt;" property. And hey presto, all the tests pass. Time to move on, right? Well, no, there's still that bit of test code above - the one that still works, because the &lt;code&gt;proxy&lt;/code&gt; still calls the "&lt;code&gt;address&lt;/code&gt;" method, and the mock object is setup to expect a call to &lt;code&gt;address&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;This is a trivial example of a problem I came across many times during maintenance. Of course, some people would say that integration testing would catch the problem, but isn't what we really want to test the fact that the property exists and returns something of a particular type? Doesn't that sound like a good job for a compiler?&lt;br /&gt;&lt;br /&gt;So much unit/integration testing I've seen on dynamically typed code is based on testing the type contracts, not the business logic. It seems like such a wasted effort to me.&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;3. "in 5 years time static compilation will be seen as a weak form of unit testing" - forget who said that - provocative but some truth to it&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;I would put it the other way - test-driven development is a weak form of typing. Look at the Scala code in the previous post. What test can I possibly write to ensure that &lt;code&gt;resetSystem&lt;/code&gt; must be called with a &lt;code&gt;User&lt;/code&gt; that has already been authorised?&lt;br /&gt;&lt;br /&gt;Or another example; what tests and defensive coding practices would you use around a list data structure that was assumed to always have at least one element in it? Using a static type system, I can write a data structure (or even better, use one from the standard library) that enforces this constraint. It would just not be possible to create an instance of this list with no elements in it (compiler error), and so any client code that ended up with an instance of one of these lists can call &lt;code&gt;get(0)&lt;/code&gt; without the need to worry about the list being empty.&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;4. metaprogramming should of course be used with utmost caution - rails is horrible in this respect - they went crazy with "monkey patching" for the sake of it - even when there we must simpler solutions. Pitty that Merb got merged into Rails - they were doing a much better job in this respect.&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;Monkey patching is a great concept that has a terrible name because of dynamically typed languages. Imagine if you could do it in a scoped way that is guaranteed by the compiler not to conflict with other "patching" on the same class. Scala has exactly &lt;a href="http://paulbarry.com/articles/2009/04/17/implicit-conversions-scalas-type-safe-answer-to-rubys-open-class"&gt;that feature&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;4. did you know that the automated refactoring came from the smalltalk world (Ralph Johnson)? Don't confuse immaturity of ruby tooling for some fundamental language weakness.&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;And was the refactoring 100% automated and effective, or did it require some human intervention or produce any false positives? It's been too long since I've programmed in SmallTalk, but I'm pretty sure I could think of cases that would be missed.&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;5. IMO the only argument in favor of static languages is performance. However I'm a self-confessed dynamic language bigot - and as one static language bigot confessed to me: ultimately it is probably just a matter of style - something to do with how our brains are wired differently as to which we prefer.&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;Before you consider what I'm about to say, bear in mind that I'm not talking about Java or C#. Both of those languages have a terrible implementation of static typing that more often that not gets in the way of what you're trying to do.&lt;br /&gt;&lt;br /&gt;So what do you consider the advantages of dynamic languages? Is it terseness? If so, I'll show you some Haskell. It certainly can't be correctness, as static typing is an encoding of a mathematical theorem; something that you can use to prove correctness (actual proofs, not failure to disprove, aka unit testing). Given the amount of additional effort of writing tests to reproduce what the compiler can do, I can't imagine that efficiency would be a benefit. Lower barrier of entry? Well, yes, I think that's the big advantage of dynamic languages. But is that something you really want to strive for?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6577188874632264829-1587021992712432900?l=kristian-domagala.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kristian-domagala.blogspot.com/feeds/1587021992712432900/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6577188874632264829&amp;postID=1587021992712432900' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6577188874632264829/posts/default/1587021992712432900'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6577188874632264829/posts/default/1587021992712432900'/><link rel='alternate' type='text/html' href='http://kristian-domagala.blogspot.com/2010/02/i-received-comment-from-past-work.html' title='Comment on previous post'/><author><name>Kristian Domagala</name><uri>http://www.blogger.com/profile/01334114225292145389</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6577188874632264829.post-5634873130214009384</id><published>2009-04-27T17:52:00.022+10:00</published><updated>2009-05-15T11:18:16.126+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='whyfp'/><category scheme='http://www.blogger.com/atom/ns#' term='types'/><category scheme='http://www.blogger.com/atom/ns#' term='rails'/><category scheme='http://www.blogger.com/atom/ns#' term='scala'/><title type='text'>Using the type system for discoverability and enforcing constraints</title><content type='html'>Now, anyone from a Ruby or other &lt;a href="http://en.wikipedia.org/wiki/Type_system#Dynamic_typing"&gt;dynamically typed language&lt;/a&gt; background who read my &lt;a href="http://kristian-domagala.blogspot.com/2009/03/filtering-list.html"&gt;last post&lt;/a&gt; might be thinking "big deal, I've been able to do that for ages". And it's true; some of these languages with support for first-class functions make writing functional code just as easy to write as it is in Scala and the like. So why would I want to use a strongly statically typed language over a dynamically typed one?&lt;br /&gt;&lt;br /&gt;Well, I'm glad you asked. Before I really got stuck into understanding functional programming and strongly statically typed languages, I spent some time working on a Rails app. Unlike most of the experiences I'd heard from people moving to Ruby/Rails though, I joined this project during the maintenance phase. What followed for me was an up-hill battle of trying to understand the code and gain the implicit knowledge of my other colleagues who worked on the code before me. The codebase left a lot to be desired in terms of discoverability. Due to the magic of meta-programming, I couldn't even rely on &lt;a href="http://en.wikipedia.org/wiki/Grep"&gt;&lt;tt&gt;grep&lt;/tt&gt;&lt;/a&gt; to find all references to a particular method.&lt;br /&gt;&lt;br /&gt;One example that remains burned into my memory was the frustration surrounding something as seemingly simple as:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;tags = item.tags&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;What is the type of &lt;tt&gt;tags&lt;/tt&gt;? Is it an array of Tag objects, an array of string tag names, or a comma separated string of tag names?&lt;br /&gt;&lt;br /&gt;The answer in my case was all of the above! What it was at runtime depended on the code path that lead to the &lt;tt&gt;tags&lt;/tt&gt; property being set on the &lt;tt&gt;item&lt;/tt&gt;. By coincidence/implicit design/whatever, it just so happened that the way it was used was consistent across the code paths that invoked it, so it never showed up as a problem until I came in one day to re-use the data in a different context. Not even the tests (which covered &gt; 98% of the code base) picked this up for me, because the tests were written upfront for the particular context that was being implemented and so it was always set to what was expected.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;It got to the point where I was so paranoid about releasing anything because I wasn't sure of all of the knock-on effects my changes would have. I was bitten too many times by not executing all of the code paths that lead to the point of my changes, because I couldn't find them all up front. I was paranoid about deleting code that I didn't think was being used any more, and even worried about factoring common-looking code out because at least on one of each of those occasions, a bug turned up either late in testing or actually in production.&lt;br /&gt;&lt;br /&gt;My flirt with mid-size scale projects in dynamically typed languages wasn't all doom and gloom though. The second rails app I worked on went a lot smoother. I put this more down to the fact that it was a green-fields project rather than because I was more familiar with the language/framework. In developing the project from the start, I had all of the assumptions and implicit knowledge about the types in my head. As a result, using the Rails framework was a breeze, and we managed to get the project completed on time and on budget.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Yes, it could be said that my first experience was just a one-off; that the previous developers didn't always stick to the conventions (whatever they're supposed to be), or were doing things in ways I wasn't aware of. But it's exactly some of these implicit assumptions and conventions that can be enforced by the compiler in a strongly statically typed language. There's no need to write your all assumptions as comments in code; many can be encoded in the language you're writing in. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Consider this code:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;# user.rb&lt;br /&gt; class User&lt;br /&gt;   def authorised?&lt;br /&gt;     ...&lt;br /&gt;   end&lt;br /&gt;   ...&lt;br /&gt; end&lt;br /&gt;&lt;br /&gt;# admin.rb&lt;br /&gt; class Admin&lt;br /&gt;   def Admin.reset_system(user)&lt;br /&gt;     check_authorisation(user)&lt;br /&gt;     ...&lt;br /&gt;     send_admin_email(user, "System was reset")&lt;br /&gt;   end&lt;br /&gt;&lt;br /&gt;   def Admin.send_admin_email(user, msg)&lt;br /&gt;     check_authorisation(user)&lt;br /&gt;     ...&lt;br /&gt;   end&lt;br /&gt;&lt;br /&gt;   def Admin.check_authorisation(user)&lt;br /&gt;     raise "Unauthorised" unless user.authorised?&lt;br /&gt;   end&lt;br /&gt; end&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Without looking at the implementation, the tests or the documentation (assuming it exists), there is no way to indicate that clients calling the &lt;tt&gt;resetSystem&lt;/tt&gt; and &lt;tt&gt;sendAdminEmail&lt;/tt&gt; functions must pass in an authorised user (never mind the fact that you don't know for sure if the methods accept a &lt;tt&gt;User&lt;/tt&gt; instance, a user identifier, or something else). Also note the authorisation check duplication. You could probably do some meta-programming to do the check before the methods are called, thus not having to worry about remembering to add the check for each authorised method in the future. However, the check is now removed from the context of the method, and it would be easy to circumvent the check if you needed to do a quick hack to get something working. Yes, the tests you (are supposed to) write should catch these problems, but they don't give you any guarantee over future changes (and from my own personal experience, the tests are a &lt;acronym title="Pain In The Arse"&gt;PITA&lt;/acronym&gt; to maintain).&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Now, imagine not only being able to get around the problems above, but to do so in a way where it is practically not possible to get the code past the compiler without it conforming to your assumptions (unless you subvert the type system, in which case you're defeating its purpose). This is the situation I've become used to in a strongly statically typed language.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;// User.scala&lt;br /&gt;  class User(...) {&lt;br /&gt;    def authorised_? = ...&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;// AuthorisedUser.scala&lt;br /&gt;  sealed abstract class AuthorisedUser(val user:User)&lt;br /&gt;&lt;br /&gt;  private class AuthorisedUserImpl(user:User) extends AuthorisedUser(user)&lt;br /&gt;&lt;br /&gt;  object AuthorisedUser {&lt;br /&gt;    def authorise(user:User):Option[AuthorisedUser] =&lt;br /&gt;        if (user.authorised_?) Some(new AuthorisedUserImpl(user)) else None&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;// Admin.scala&lt;br /&gt;  object Admin {&lt;br /&gt;    def resetSystem(user:AuthorisedUser) = {&lt;br /&gt;      ...&lt;br /&gt;      sendAdminEmail(user, "System was reset")&lt;br /&gt;    }&lt;br /&gt;    def sendAdminEmail(user:AuthorisedUser, msg:String) = ...&lt;br /&gt;  }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;A quick note about the Scala syntax again:&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;Scala makes the distinction between &lt;tt&gt;object&lt;/tt&gt;s and &lt;tt&gt;class&lt;/tt&gt;es, where the former declares a singleton and only defines static functions (eg. &lt;tt&gt;authorise&lt;/tt&gt;), and the latter can be instantiated and defines instance methods (eg. &lt;tt&gt;authorised_?&lt;/tt&gt;). Java does not make this distinction; a &lt;tt&gt;class&lt;/tt&gt; can define both static functions and instance methods.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;The &lt;tt&gt;sealed&lt;/tt&gt; keyword denotes a class that cannot be extended from outside of the file it is defined in. In this case, as a client, you cannot circumvent the authorisation check by creating another subclass of &lt;tt&gt;AuthorisedUser&lt;/tt&gt; to pass in to the restricted functions.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;a href="http://www.scala-lang.org/docu/files/api/scala/Some.html"&gt;&lt;tt&gt;Some&lt;/tt&gt;&lt;/a&gt; and &lt;a href="http://www.scala-lang.org/docu/files/api/scala/None.html"&gt;&lt;tt&gt;None&lt;/tt&gt;&lt;/a&gt; are subclasses of the &lt;a href="http://www.scala-lang.org/docu/files/api/scala/Option.html"&gt;&lt;tt&gt;Option&lt;/tt&gt;&lt;/a&gt; type in Scala. In this case, it allows an optional &lt;tt&gt;AuthorisedUser&lt;/tt&gt; to be returned from the &lt;tt&gt;authorise&lt;/tt&gt; function depending on whether or not the underlying user is authorised.&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;From the above code, it is just not practically possible to write client code that calls the &lt;tt&gt;resetSystem&lt;/tt&gt; and &lt;tt&gt;sendAdminEmail&lt;/tt&gt; functions without first calling the &lt;tt&gt;authorise&lt;/tt&gt; function. If you try, your code won't compile. None of this finding out at test-time/run-time - it can't run, because it won't compile.&lt;br /&gt;&lt;br /&gt;Not only that, but the compiler actually removes the need to test authorisation checks for the &lt;tt&gt;Admin&lt;/tt&gt; functions. There are no tests to write that would make sense; either the user is authorised, or the code doesn't compile!&lt;br /&gt;&lt;br /&gt;As you can see, in this case the statically typed language allows more assumptions to be made explicit in the code. If I decide to do a one-off hack, the compiler can be used to keep me honest, and I've found that it generally makes me think more about the problem I'm trying to solve. Yes, it can be frustrating trying to get your code to pass the compiler (especially when you think it's right), but more often than not, when it does compile, I am a lot more confident that it is correct in terms of being consistent with my assumptions. The type system can also be seen as the ultimate defensive coding practice. With a type system, discussions &lt;a href="http://news.ycombinator.com/item?id=561277"&gt;like&lt;/a&gt; &lt;a href="http://www.reddit.com/r/programming/comments/8cm8w/defensive_coding_is_a_code_smell/#"&gt;these&lt;/a&gt; tend to become moot.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;The most common objection I've come across to using a statically typed language over a dynamically typed language is that the former is more verbose and requires more code to achieve the same functionality in the latter. This is only true of languages with a poor type system implementation, and has already been addressed many times before. I wasn't going to mention it, but for those who didn't notice, the strongly-statically typed version above actually has fewer lines of code than the dynamically typed version. It also requires fewer tests (because there's no way to call the admin functions with an unauthorised user) and has all the other benefits of statically compiled code. Win-win-win.&lt;br /&gt;&lt;br /&gt;Whilst there will be more examples of some of the advantages you can get from the type system, I don't plan to write too much more on the specific topic of Dynamic vs. Static types as it has already been covered many times before. I am very open to criticisms of the above comparison, as long as it focuses on the topic at hand, not the actual implementation (it is one of the smaller examples I could come up with to try get my point across, and as such, it is somewhat contrived).&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="font-size:85%;"&gt;&lt;br /&gt;Also note that you can get these benefits in a language with a weaker type system, such as Java. However, the ceremony involved in declaring the types usually makes it infeasible to do for the trivial cases and painful for the complex cases. Below you can see the previous Scala code that has been ported to Java, making use of the &lt;a href="http://functionaljava.org/"&gt;FunctionalJava&lt;/a&gt; library:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;// User.java&lt;br /&gt;  public class User {&lt;br /&gt;    public boolean isAuthorised() {&lt;br /&gt;      ...&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;// AuthorisedUser.java&lt;br /&gt;  public abstract class AuthorisedUser {&lt;br /&gt;    final User user;&lt;br /&gt; &lt;br /&gt;    private AuthorisedUser(final User user) {&lt;br /&gt;      this.user = user;&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    private static class AuthorisedUserImpl extends AuthorisedUser {&lt;br /&gt;      public AuthorisedUserImpl(final User user) {&lt;br /&gt;        super(user);&lt;br /&gt;      }&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    public static Option&amp;lt;AuthorisedUser&amp;gt; authorise(final User user) {&lt;br /&gt;      return user.isAuthorised()&lt;br /&gt;          ? Option.&amp;lt;AuthorisedUser&amp;gt;some(new AuthorisedUserImpl(user))&lt;br /&gt;          : Option.&amp;lt;AuthorisedUser&amp;gt;none();&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;// Admin.java&lt;br /&gt;  public class Admin {&lt;br /&gt; &lt;br /&gt;    public static void resetSystem(final AuthorisedUser user) {&lt;br /&gt;      ...&lt;br /&gt;      sendAdminEmail(user);&lt;br /&gt;    }&lt;br /&gt; &lt;br /&gt;    public static void sendAdminEmail(final AuthorisedUser user) {&lt;br /&gt;      ...&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;&lt;/pre&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/6577188874632264829-5634873130214009384?l=kristian-domagala.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kristian-domagala.blogspot.com/feeds/5634873130214009384/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6577188874632264829&amp;postID=5634873130214009384' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6577188874632264829/posts/default/5634873130214009384'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6577188874632264829/posts/default/5634873130214009384'/><link rel='alternate' type='text/html' href='http://kristian-domagala.blogspot.com/2009/04/using-type-system-for-discoverability.html' title='Using the type system for discoverability and enforcing constraints'/><author><name>Kristian Domagala</name><uri>http://www.blogger.com/profile/01334114225292145389</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6577188874632264829.post-3939787736192696468</id><published>2009-03-13T16:28:00.016+10:00</published><updated>2009-03-14T09:01:47.982+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='fp'/><category scheme='http://www.blogger.com/atom/ns#' term='whyfp'/><category scheme='http://www.blogger.com/atom/ns#' term='scala'/><title type='text'>Filtering a list</title><content type='html'>Ok, let's start off with an easy one. How many times have you written something like the following:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;  public Iterable&amp;lt;User&amp;gt; getManagers(Iterable&amp;lt;User&amp;gt; users) {&lt;br /&gt;    List&amp;lt;User&amp;gt; managers = new ArrayList&amp;lt;User&amp;gt;();&lt;br /&gt;    for (User user : users) {&lt;br /&gt;      if (user.isManager()) {&lt;br /&gt;        managers.add(user);&lt;br /&gt;      }&lt;br /&gt;    }&lt;br /&gt;    return managers;&lt;br /&gt;  }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;I know I've written a lot of code like that in the past. Each time, there's something slightly different. Either the types are different or the test in the &lt;tt&gt;if&lt;/tt&gt; statement is different. For example, imagine a similar requirement to get the list of active users. There doesn't appear to be much more you can do aside from:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;  public Iterable&amp;lt;User&amp;gt; getActiveUsers(Iterable&amp;lt;User&amp;gt; users) {&lt;br /&gt;    List&amp;lt;User&amp;gt; activeUsers = new ArrayList&amp;lt;User&amp;gt;();&lt;br /&gt;    for (User user : users) {&lt;br /&gt;      if (user.isActive()) {&lt;br /&gt;        activeUsers.add(user);&lt;br /&gt;      }&lt;br /&gt;    }&lt;br /&gt;    return activeUsers;&lt;br /&gt;  }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Well, there is some stuff we can factor out if we really wanted to:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;  private static interface Condition {&lt;br /&gt;    boolean check(User user);&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  private Iterable&amp;lt;User&amp;gt; filterUsers(Iterable&amp;lt;User&amp;gt; users, Condition cond) {&lt;br /&gt;    List&amp;lt;User&amp;gt; filteredUsers = new ArrayList&amp;lt;User&amp;gt;();&lt;br /&gt;    for (User user : users) {&lt;br /&gt;      if (cond.check(user)) {&lt;br /&gt;        filteredUsers.add(user);&lt;br /&gt;      }&lt;br /&gt;    }&lt;br /&gt;    return filteredUsers;&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  public Iterable&amp;lt;User&amp;gt; getManagers(Iterable&amp;lt;User&amp;gt; users) {&lt;br /&gt;    return filterUsers(users, new Condition() {&lt;br /&gt;      public boolean check(User user) {&lt;br /&gt;        return user.isManager();&lt;br /&gt;      }&lt;br /&gt;    });&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  public Iterable&amp;lt;User&amp;gt; getActiveUsers(Iterable&amp;lt;User&amp;gt; users) {&lt;br /&gt;    return filterUsers(users, new Condition() {&lt;br /&gt;      public boolean check(User user) {&lt;br /&gt;        return user.isActive();&lt;br /&gt;      }&lt;br /&gt;    });&lt;br /&gt;  }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;However, given that it's more code than the two original methods, I probably wouldn't actually do that unless I had a lot of similar looking methods. In any case, there's still duplication in the creation of the conditions. Without resorting to reflection (which would instantly open myself up to a whole new class of bugs), I can't think of much more that can be done with this code in Java.&lt;br /&gt;&lt;br /&gt;In terms of the bounds of readability I mentioned in my &lt;a href="http://kristian-domagala.blogspot.com/2009/03/moral-dilemma.html"&gt;dilemma&lt;/a&gt;, I would have left it at the first two methods and moved on.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Now take a look at the same two methods written in Scala; a language that supports &lt;a href="http://en.wikipedia.org/wiki/First-class_function"&gt;first class functions&lt;/a&gt;:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;  def getManagers(users:List[User]):List[User] = {&lt;br /&gt;    return users.filter(isUserManager);&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  def getActiveUsers(users:List[User]):List[User] = {&lt;br /&gt;    return users.filter((user:User) =&gt; user.isActive());&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  def isUserManager(user:User):Boolean = {&lt;br /&gt;    return user.isManager();&lt;br /&gt;  }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;First, some quick notes about the syntax:&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;The &lt;tt&gt;def&lt;/tt&gt; keyword is used to declare a function or a method&lt;/li&gt;&lt;br /&gt;&lt;li&gt;In Scala, type annotations come at the end of the parameter and function declarations (after the '&lt;tt&gt;:&lt;/tt&gt;' character)&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Generics in Scala are expressed using square brackets as opposed to Java's angle brackets&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;On to the semantics of the code. The &lt;tt&gt;&lt;a href="http://www.scala-lang.org/docu/files/api/scala/List.html#filter((A)%3D%3EBoolean)"&gt;filter&lt;/a&gt;&lt;/tt&gt; function on Scala's &lt;tt&gt;&lt;a href="http://www.scala-lang.org/docu/files/api/scala/List.html"&gt;List&lt;/a&gt;&lt;/tt&gt; class is a &lt;a href="http://en.wikipedia.org/wiki/Higher-order_function"&gt;higher-order function&lt;/a&gt;, which in this case it means that it is a function that takes another function as a parameter. In the first case, you can see how the parameter to the &lt;tt&gt;filter&lt;/tt&gt; function is another named function that is defined later on. In the second case, the parameter is defined in-line as an anonymous (unnamed) function.&lt;br /&gt;&lt;br /&gt;In this example, the type of the parameter that &lt;tt&gt;List.filter&lt;/tt&gt; expects is:&lt;br /&gt;&lt;br /&gt;A &lt;span style="font-weight:bold;"&gt;function&lt;/span&gt;, which takes a single &lt;span style="font-weight:bold;"&gt;&lt;tt&gt;User&lt;/tt&gt; parameter&lt;/span&gt;, and &lt;span style="font-weight:bold;"&gt;returns&lt;/span&gt; a &lt;span style="font-weight:bold;"&gt;&lt;tt&gt;Boolean&lt;/tt&gt;&lt;/span&gt; value.&lt;br /&gt;&lt;br /&gt;In the example, the &lt;tt&gt;List.filter&lt;/tt&gt; function returns a (possibly empty) &lt;span style="font-weight:bold;"&gt;&lt;tt&gt;List&lt;/tt&gt;&lt;/span&gt; of &lt;span style="font-weight:bold;"&gt;&lt;tt&gt;User&lt;/tt&gt;&lt;/span&gt; objects.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;I intentionally wrote out the Scala code in a verbose manner to try to make it easier read if you're coming from Java. However, in most cases there are a lot of aspects of the Scala syntax that are optional, such as semicolons, the return keyword, braces for single statements, and return types when they can be inferred. As someone who is more comfortable with the language, I find it easier to write it and at least as easy to read it as:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;  def getManagers(users:List[User]) = users.filter(isUserManager)&lt;br /&gt;  def getActiveUsers(users:List[User]) = users.filter((user:User) =&gt; user.isActive())&lt;br /&gt;  def isUserManager(user:User) = user.isManager()&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Actually, I would probably inline the &lt;tt&gt;isUserManager&lt;/tt&gt; function because it's almost like an alias now, and because the &lt;tt&gt;user&lt;/tt&gt; parameter in the anonymous function is only used once and the type of it can be inferred, the last function can be shortened further still:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;  def getManagers(users:List[User]) = users.filter(_.isManager())&lt;br /&gt;  def getActiveUsers(users:List[User]) = users.filter(_.isActive())&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Now, imagine getting used to writing code like that and then coming back to this:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;  public Iterable&amp;lt;User&amp;gt; getManagers(Iterable&amp;lt;User&amp;gt; users) {&lt;br /&gt;    List&amp;lt;User&amp;gt; managers = new ArrayList&amp;lt;User&amp;gt;();&lt;br /&gt;    for (User user : users) {&lt;br /&gt;      if (user.isManager()) {&lt;br /&gt;        managers.add(user);&lt;br /&gt;      }&lt;br /&gt;    }&lt;br /&gt;    return managers;&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  public Iterable&amp;lt;User&amp;gt; getActiveUsers(Iterable&amp;lt;User&amp;gt; users) {&lt;br /&gt;    List&amp;lt;User&amp;gt; activeUsers = new ArrayList&amp;lt;User&amp;gt;();&lt;br /&gt;    for (User user : users) {&lt;br /&gt;      if (user.isActive()) {&lt;br /&gt;        activeUsers.add(user);&lt;br /&gt;      }&lt;br /&gt;    }&lt;br /&gt;    return activeUsers;&lt;br /&gt;  }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;And, if you'll allow me to mix my metaphors, this is barely scratching the tip of the iceberg.&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/6577188874632264829-3939787736192696468?l=kristian-domagala.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kristian-domagala.blogspot.com/feeds/3939787736192696468/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6577188874632264829&amp;postID=3939787736192696468' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6577188874632264829/posts/default/3939787736192696468'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6577188874632264829/posts/default/3939787736192696468'/><link rel='alternate' type='text/html' href='http://kristian-domagala.blogspot.com/2009/03/filtering-list.html' title='Filtering a list'/><author><name>Kristian Domagala</name><uri>http://www.blogger.com/profile/01334114225292145389</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6577188874632264829.post-4754973554779353390</id><published>2009-03-04T20:30:00.006+10:00</published><updated>2009-03-05T12:57:00.128+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='whyfp'/><title type='text'>Moral dilemma</title><content type='html'>I have found myself in the unfortunate position of being asked to dumb-down the work that I do so it is understandable to an "average" programmer (whatever that means). I understand where the request is coming from, ie, there is a fear that if it's not dumbed down, there will be a difficulty in finding someone to understand and maintain the work in the future. However, for me to comply with the request would mean to knowingly write code that is less correct, contain more duplication (both in terms of the effort and the resulting code), and have more known potential traps for future maintenance - something that the "average" programmer would tell you is a "bad thing".&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;How did I find myself in this position?&lt;/h2&gt;&lt;br /&gt;In the past, I would try to adhere to the principles of &lt;a href="http://en.wikipedia.org/wiki/Don%27t_repeat_yourself"&gt;&lt;acronym title="Don't Repeat Yourself"&gt;DRY&lt;/acronym&gt;&lt;/a&gt;, but on a number of occasions, I would get to the point where in order to avoid repetition, I had to bend the language that I used in ways it wasn't designed for. The resulting code would end up being verbose and very difficult to understand after time, and I still wasn't achieving the re-use that I thought should be possible. In the end, I learned roughly where some of those boundaries of readability lay, and resigned myself to the belief that the duplication was a fact of life.&lt;a href="#footnote1" name="footnote1_return"&gt;&lt;sup&gt;1&lt;/sup&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Then, about a year ago, I was lucky enough to spend a bit of time learning about &lt;a href="http://en.wikipedia.org/wiki/Functional_programming"&gt;Functional Programming&lt;/a&gt; and &lt;a href="http://en.wikipedia.org/wiki/Type_system"&gt;Strong, Static Type Systems&lt;/a&gt; with &lt;a href="http://tmorris.net/"&gt;someone&lt;/a&gt; who is a self confessed &lt;a href="http://blog.xebia.com/2008/11/30/qcon-sf-return-of-the-fundamentalist-functional-programmer/"&gt;fundamentalist functional programmer&lt;/a&gt;. Over many months, I was able to change the way I thought about programming. My progress was very slow to begin with, and I found that a lot of the discussions and reading I was doing on the subject were out of reach of my understanding. However, through continual encouragement, and when I finally started doing the excercises and writing small programs in this new way, things started to sink in and make sense. I didn't change my way of thinking in a single &lt;a href="http://en.wikipedia.org/wiki/Eureka_(word)"&gt;Eureka!&lt;/a&gt; moment, but more in a series of small "A ha, now I think I get it" moments.&lt;br /&gt;&lt;br /&gt;Now I can write far more concise code using very powerful abstractions, with the added benefit that a large class of potential bugs don't even get past the compiler.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;What am I going to do about it?&lt;/h2&gt;&lt;br /&gt;Back to my dilemma. Obviously, if I want to do something about it, I need to present my argument in a convincing way. I don't have a way of showing the whole picture in a single, simple, succinct way. In fact, I'm very doubtful that such a way exists. There was a lot of unlearning I had to do before I could really begin to see the benefits of functional programming.&lt;br /&gt;&lt;br /&gt;I had planned to write up my experiences along the way while I was learning, but I didn't think I could do any better than what other people have &lt;a href="http://www.defmacro.org/ramblings/fp.html"&gt;already put out there&lt;/a&gt;; people who have come to the same conclusions and made the same observations that I have. Having been forced back into the position of writing imperative code though has given me a good reason to get my thoughts down in writing.&lt;br /&gt;&lt;br /&gt;So, with that in mind, I'm planning to write up some examples of situations I've come across, where I have relented and written repetitive, less correct, or more error prone code in order to fulfill the contradictory requirements that lead to my dilemma. Using these examples, I hope to build a case for using languages that support functional programming and strong, static type systems even if these languages aren't popular or in the mainstream.&lt;br /&gt;&lt;br /&gt;From the personal experience of someone who heavily bought into &lt;a href="http://en.wikipedia.org/wiki/Test-driven_development"&gt;&lt;acronym title="Test Driven Development/Design"&gt;TDD&lt;/acronym&gt;&lt;/a&gt;, &lt;a href="http://en.wikipedia.org/wiki/OOAD"&gt;&lt;acronym title="Object Oriented Analysis and Design"&gt;OOAD&lt;/acronym&gt;&lt;/a&gt;, &lt;a href="http://en.wikipedia.org/wiki/Design_pattern_(computer_science)"&gt;Design Patterns&lt;/a&gt;, etc, I can predict that some of the examples will look wrong, or completely opposite to what is regarded as "best practice" in the mainstream. I will try to identify those areas and drill down into them when I get a chance. In the meantime, you should at least be prepared to question your current knowledge.&lt;br /&gt;&lt;br /&gt;This is not going to be another &lt;a href="http://byorgey.wordpress.com/2009/01/12/abstraction-intuition-and-the-monad-tutorial-fallacy/"&gt;burrito tutorial&lt;/a&gt;, and I can almost guarantee that anyone who reads &lt;span style="font-style:italic;"&gt;only&lt;/span&gt; what I plan to write will not come away with an understanding of Functional Programming. The aim is to show some of the possibilities and maybe encourage people to look further into the context that makes it possible.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Meta&lt;/h2&gt;&lt;br /&gt;&lt;span style="font-size:90%;"&gt;I haven't really thought of a logical sequence, so things may seem out of order. However, I'll try to come back and provide cross-links to follow-ups and related entries.&lt;br /&gt;&lt;br /&gt;Also, although there's not many existing entries in this blog, I'll use the tag &lt;a href="http://kristian-domagala.blogspot.com/search/label/whyfp"&gt;whyfp&lt;/a&gt; (as in, &lt;a href="http://www.cs.chalmers.se/~rjmh/Papers/whyfp.html"&gt;Why Functional Programming Matters&lt;/a&gt;) to mark each entry that is related to my dilemma.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;a name="footnote1" href="#footnote1_return"&gt;&lt;sup&gt;1&lt;/sup&gt;&lt;/a&gt; &lt;span style="font-size:85%;"&gt;Interestingly, I recently read a &lt;a href="http://turbulentintellect.blogspot.com/2008/06/incidental-redundancy.html"&gt;blog post&lt;/a&gt; that discusses duplication/redundancy, by someone who seems to have come to similar conclusions that I came to. If I understand correctly, they refer to this as incidental redundancy, and conclude that you can't, and shouldn't, do anything about it. However, I now know that some redundancy that I previously thought was incidental, is in fact related and if you discover or know the abstractions and use a language that allows the abstractions to be easily expressed, the redundancy is avoidable.&lt;/span&gt;&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/6577188874632264829-4754973554779353390?l=kristian-domagala.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kristian-domagala.blogspot.com/feeds/4754973554779353390/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6577188874632264829&amp;postID=4754973554779353390' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6577188874632264829/posts/default/4754973554779353390'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6577188874632264829/posts/default/4754973554779353390'/><link rel='alternate' type='text/html' href='http://kristian-domagala.blogspot.com/2009/03/moral-dilemma.html' title='Moral dilemma'/><author><name>Kristian Domagala</name><uri>http://www.blogger.com/profile/01334114225292145389</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6577188874632264829.post-1475357039436492866</id><published>2008-10-28T16:57:00.001+10:00</published><updated>2008-10-28T17:00:42.354+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='bash'/><category scheme='http://www.blogger.com/atom/ns#' term='find'/><category scheme='http://www.blogger.com/atom/ns#' term='commandline'/><title type='text'>Finding large files</title><content type='html'>Yet another thing I keep forgetting:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;  find . -size +10000k&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Finds files over roughly 10Mb&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/6577188874632264829-1475357039436492866?l=kristian-domagala.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kristian-domagala.blogspot.com/feeds/1475357039436492866/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6577188874632264829&amp;postID=1475357039436492866' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6577188874632264829/posts/default/1475357039436492866'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6577188874632264829/posts/default/1475357039436492866'/><link rel='alternate' type='text/html' href='http://kristian-domagala.blogspot.com/2008/10/finding-large-files.html' title='Finding large files'/><author><name>Kristian Domagala</name><uri>http://www.blogger.com/profile/01334114225292145389</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6577188874632264829.post-4681176057399718866</id><published>2008-10-24T08:45:00.007+10:00</published><updated>2008-10-24T09:18:05.986+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='hibernate'/><category scheme='http://www.blogger.com/atom/ns#' term='scala'/><title type='text'>Proxy instantiation problem from Hibernate Session load</title><content type='html'>This one had me puzzled for a while yesterday. I was able to retrieve objects from a &lt;tt&gt;Session&lt;/tt&gt; via a query, but I was getting the following error when I was using the &lt;a href="http://www.hibernate.org/hib_docs/v3/api/org/hibernate/Session.html#load(java.lang.Class,%20java.io.Serializable)"&gt;&lt;tt&gt;load&lt;/tt&gt;&lt;/a&gt; method:&lt;br /&gt;&lt;pre&gt;&lt;div style="overflow:auto;width:100%;"&gt;&lt;br /&gt;org.hibernate.HibernateException: Javassist Enhancement failed: Thing&lt;br /&gt;        at org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer.getProxy(JavassistLazyInitializer.java:142)&lt;br /&gt;        at org.hibernate.proxy.pojo.javassist.JavassistProxyFactory.getProxy(JavassistProxyFactory.java:72)&lt;br /&gt;        at org.hibernate.tuple.entity.AbstractEntityTuplizer.createProxy(AbstractEntityTuplizer.java:402)&lt;br /&gt;        at org.hibernate.persister.entity.AbstractEntityPersister.createProxy(AbstractEntityPersister.java:3483)&lt;br /&gt;        at org.hibernate.event.def.DefaultLoadEventListener.createProxyIfNecessary(DefaultLoadEventListener.java:298)&lt;br /&gt;        at org.hibernate.event.def.DefaultLoadEventListener.proxyOrLoad(DefaultLoadEventListener.java:219)&lt;br /&gt;        at org.hibernate.event.def.DefaultLoadEventListener.onLoad(DefaultLoadEventListener.java:126)&lt;br /&gt;        at org.hibernate.impl.SessionImpl.fireLoad(SessionImpl.java:905)&lt;br /&gt;        at org.hibernate.impl.SessionImpl.load(SessionImpl.java:822)&lt;br /&gt;        at org.hibernate.impl.SessionImpl.load(SessionImpl.java:815)&lt;br /&gt;...&lt;br /&gt;Caused by: java.lang.InstantiationException: Thing_$$_javassist_0&lt;br /&gt;        at java.lang.Class.newInstance0(Class.java:335)&lt;br /&gt;        at java.lang.Class.newInstance(Class.java:303)&lt;br /&gt;        at org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer.getProxy(JavassistLazyInitializer.java:139)&lt;br /&gt;        ... 49 more&lt;br /&gt;&lt;/div&gt;&lt;/pre&gt;&lt;br /&gt;When I changed the code from&lt;pre&gt;&lt;br /&gt;  session.load(classOf[Thing], id).asInstanceOf[Thing]&lt;br /&gt;&lt;/pre&gt; to &lt;pre&gt;&lt;div style="overflow:auto;width:100%;"&gt;&lt;br /&gt;  session.createQuery("from Thing where id = " + id).list().asInstanceOf[java.util.List[Thing]].toList(1)&lt;br /&gt;&lt;/div&gt;&lt;/pre&gt;everything worked as expected.&lt;br /&gt;&lt;br /&gt;I found a few results from the web, but nothing to indicate what my specific problem was.&lt;br /&gt;&lt;br /&gt;The code I was working on was loosely based on another Scala project, which uses an older version of Hibernate. I changed the libraries over, and got a similar problem with CGLIB:&lt;br /&gt;&lt;pre&gt;&lt;div style="overflow:auto;width:100%;"&gt;&lt;br /&gt;org.hibernate.HibernateException: CGLIB Enhancement failed: Thing&lt;br /&gt;        at org.hibernate.proxy.pojo.cglib.CGLIBLazyInitializer.getProxy(CGLIBLazyInitializer.java:96)&lt;br /&gt;        at org.hibernate.proxy.pojo.cglib.CGLIBProxyFactory.getProxy(CGLIBProxyFactory.java:49)&lt;br /&gt;        at org.hibernate.tuple.entity.AbstractEntityTuplizer.createProxy(AbstractEntityTuplizer.java:379)&lt;br /&gt;        at org.hibernate.persister.entity.AbstractEntityPersister.createProxy(AbstractEntityPersister.java:3455)&lt;br /&gt;        at org.hibernate.event.def.DefaultLoadEventListener.createProxyIfNecessary(DefaultLoadEventListener.java:257)&lt;br /&gt;        at org.hibernate.event.def.DefaultLoadEventListener.proxyOrLoad(DefaultLoadEventListener.java:191)&lt;br /&gt;        at org.hibernate.event.def.DefaultLoadEventListener.onLoad(DefaultLoadEventListener.java:103)&lt;br /&gt;        at org.hibernate.impl.SessionImpl.fireLoad(SessionImpl.java:878)&lt;br /&gt;        at org.hibernate.impl.SessionImpl.load(SessionImpl.java:795)&lt;br /&gt;        at org.hibernate.impl.SessionImpl.load(SessionImpl.java:788)&lt;br /&gt;...&lt;br /&gt;Caused by: java.lang.InstantiationException: Thing$$EnhancerByCGLIB$$e29dbda1&lt;br /&gt;        at java.lang.Class.newInstance0(Class.java:335)&lt;br /&gt;        at java.lang.Class.newInstance(Class.java:303)&lt;br /&gt;        at org.hibernate.proxy.pojo.cglib.CGLIBLazyInitializer.getProxyInstance(CGLIBLazyInitializer.java:107)&lt;br /&gt;        at org.hibernate.proxy.pojo.cglib.CGLIBLazyInitializer.getProxy(CGLIBLazyInitializer.java:93)&lt;br /&gt;        ... 49 more&lt;br /&gt;&lt;/div&gt;&lt;/pre&gt;&lt;br /&gt;This time I was luckier with my search results, which eventually lead me to these &lt;a href="http://opensource.atlassian.com/projects/hibernate/browse/HHH-1680"&gt;two&lt;/a&gt; &lt;a href="http://forum.hibernate.org/viewtopic.php?p=2263799&amp;sid=2666b2466f7d14630dd37f795802fc4d"&gt;pages&lt;/a&gt;. Indeed, the problem was due to having a private no-args constructor in my Thing object. As soon as I changed the constructor to be visable, the calls to &lt;tt&gt;load()&lt;/tt&gt; started working as expected.&lt;br /&gt;&lt;br /&gt;I was thrown a bit by the &lt;tt&gt;InstantiationException&lt;/tt&gt;, which according to the &lt;a href="http://software.workingmouse.com/docs/j2se/1.5.0/api/java/lang/InstantiationException.html"&gt;JavaDoc&lt;/a&gt; is&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;Thrown when an application tries to create an instance of a class using the newInstance method in class Class, but the specified class object cannot be instantiated because it is an interface or is an abstract class.&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;While I can see that it's related, I don't really think the private constructor issue strictly falls under that description. In any case, I'm sure that a better message, or a different exception, or an update to the documentation, would have helped me isolate the problem a lot quicker.&lt;br /&gt;&lt;br /&gt;Oddly, the code from the other project also has a private no-args constructor, yet it seems to work. That part remains a mystery to me, but I thought I'd post my other findings in case it helps anyone else who runs into a similar issue.&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/6577188874632264829-4681176057399718866?l=kristian-domagala.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kristian-domagala.blogspot.com/feeds/4681176057399718866/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6577188874632264829&amp;postID=4681176057399718866' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6577188874632264829/posts/default/4681176057399718866'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6577188874632264829/posts/default/4681176057399718866'/><link rel='alternate' type='text/html' href='http://kristian-domagala.blogspot.com/2008/10/proxy-instantiation-problem-from.html' title='Proxy instantiation problem from Hibernate Session load'/><author><name>Kristian Domagala</name><uri>http://www.blogger.com/profile/01334114225292145389</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6577188874632264829.post-2966372739943329441</id><published>2008-10-16T20:55:00.011+10:00</published><updated>2008-10-24T09:18:31.927+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='mercurial'/><category scheme='http://www.blogger.com/atom/ns#' term='bash'/><category scheme='http://www.blogger.com/atom/ns#' term='commandline'/><category scheme='http://www.blogger.com/atom/ns#' term='growl'/><category scheme='http://www.blogger.com/atom/ns#' term='mac'/><category scheme='http://www.blogger.com/atom/ns#' term='vcs'/><title type='text'>Home directory version control notification</title><content type='html'>I spent some time in admin mode recently, seeing if I could improve the way my home directory is versioned. Previously, I had a few Mercurial repositories scattered around the place to track my documents, scripts, config and miscellaneous files.&lt;br /&gt;&lt;br /&gt;Most of my work-related directories have their own Subversion repositories attached to them, but there were also some scratch projects that weren't under any &lt;acronym title="Version Control System"&gt;VCS&lt;/acronym&gt;. My config files (eg, .bashrc) were sym-linked to a separate directory that had its own repository.&lt;br /&gt;&lt;br /&gt;The main problems I had with the different repositories is that I didn't have an easy way to determine if I had any outstanding changes that need to be committed (my documents directory was shockingly out of date), and there were things that I wanted versioned (for example, application preferences) that weren't being versioned.&lt;br /&gt;&lt;br /&gt;My first thought was to add a single Mercurial repository at the root of my home directory so I only had one repository to remember, and could easily track anything that gets added over time (for example, config files for new programs). Once I started thinking about all of the entries in my ignore file though, and how I wanted to share some stuff between work and home but not others, this option became less and less appealing.&lt;br /&gt;&lt;br /&gt;So, back to the multiple repositories it was. What I ended up was repositories for the following directories:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;  ~/Documents&lt;br /&gt;  ~/Library&lt;br /&gt;  ~/home&lt;br /&gt;  ~/projects&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The &lt;tt&gt;~/Library&lt;/tt&gt; directory is the standard directory on OSX for storing application support files, preferences, etc, and while I'm not particularly interested in the day-to-day happenings of this directory, it is helpful to have snap-shots that I can revert to at a later date.&lt;br /&gt;&lt;br /&gt;I'm using the &lt;tt&gt;home&lt;/tt&gt; repository to track utility scripts and dot files that live directly under &lt;tt&gt;~&lt;/tt&gt; (mostly run config and history files). Almost all dot files in my &lt;tt&gt;~&lt;/tt&gt; directory are sym-linked to somewhere in my home repository, and I have a bootstrap script to take care of this if I need to setup another home directory on a different machine in the future.&lt;br /&gt;&lt;br /&gt;Finding out how to merge my old scripts and config repositories (whilst retaining their histories) was not a simple exercise. I thought I might be able to use Mercurial's &lt;tt&gt;import&lt;/tt&gt; and &lt;tt&gt;export&lt;/tt&gt; commands to merge one into the other, but there doesn't appear to be a way of specifying a relative path to import a repository at, so when I tried, I ended up with everything in the root of the repository. In hindsight, I realise I could have created a new repository and imported both repositories there, making sure to move the contents straight after importing, but there was another &lt;a href="http://www.selenic.com/mercurial/wiki/index.cgi/MergingUnrelatedRepositories"&gt;similar solution&lt;/a&gt; that I eventually found and got to work.&lt;br /&gt;&lt;br /&gt;Now that I was happy with my repositories layout, I wanted a way to make sure they were kept up to date. At first I thought about adding a &lt;tt&gt;cron&lt;/tt&gt; job that adds, removes, and commits changes automatically at given periods. Then I thought that might lead to stuff being committed that I didn't want (for example, if I generated a large amount of data that slipped through my ignore file), and having a repository log full of static messages. So instead, I decided to go with a notification approach instead.&lt;br /&gt;&lt;br /&gt;Finding uncommitted changes was pretty straight forward with the following command:&lt;br /&gt;&lt;pre&gt;&lt;div style="overflow:auto;width:100%;"&gt;&lt;br /&gt;  find . -name .hg -not -path "./Library/.hg" -exec /opt/local/bin/hg st {}/.. \;&lt;br /&gt;&lt;/div&gt;&lt;/pre&gt;&lt;br /&gt;(I took the Library repository out of the results because I didn't want to be bugged about those changes throughout the day; instead, I just take a snapshot of that at the end of each day).&lt;br /&gt;&lt;br /&gt;This has the added benefit that if I add more Mercurial repositories in the future, they'll automatically be included in the notification without me having to change anything.&lt;br /&gt;&lt;br /&gt;Next up, notification. I find &lt;a href="http://growl.info"&gt;Growl&lt;/a&gt; on the Mac to be useful for receiving reasonably unobtrusive notifications throughout the day. It ships with a command-line interface (that you need to install separately), which was perfect for what I needed:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;  /usr/local/bin/growlnotify "Uncommitted Changes" &lt;$CHANGES_FILE&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;tt&gt;$CHANGES_FILE&lt;/tt&gt; holds the output of the previous &lt;tt&gt;find&lt;/tt&gt; command. I wanted it stored so I could also copy the changes to my desktop, giving me a secondary visual cue that I have changes outstanding in case I missed the Growl notification.&lt;br /&gt;&lt;br /&gt;I ended up with the following bit of script (after adding a few finishing touches, such as using a temp file for the intermediate results, only notifying if the size of the changes file is greater than zero, and displaying the notification with a nice Mercurial icon):&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;  TMP_FILE=`mktemp /tmp/uncommitted_changes.XXXXXX` || exit 1&lt;br /&gt;  &lt;br /&gt;  cd $HOME&lt;br /&gt;  find . -name .hg -not -path "./Library/.hg" \&lt;br /&gt;      -exec /opt/local/bin/hg st {}/.. \; &gt;$TMP_FILE&lt;br /&gt;  &lt;br /&gt;  if [[ -s $TMP_FILE ]]; then&lt;br /&gt;    CHANGES_FILE=$HOME/Desktop/uncommitted_changes.txt&lt;br /&gt;    mv $TMP_FILE $CHANGES_FILE&lt;br /&gt;    /usr/local/bin/growlnotify \&lt;br /&gt;        --image $HOME/bin/img/hg-icon-50.png \&lt;br /&gt;        "Uncommitted Changes" &lt;$CHANGES_FILE &gt; /dev/null 2&gt;&amp;1&lt;br /&gt;  else&lt;br /&gt;    rm $TMP_FILE&lt;br /&gt;  fi&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;And here it is in action:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_TkDxSqrQ5lE/SPbD4bbx9SI/AAAAAAAAAC4/QZlasfESMjA/s1600-h/Picture+1.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://3.bp.blogspot.com/_TkDxSqrQ5lE/SPbD4bbx9SI/AAAAAAAAAC4/QZlasfESMjA/s320/Picture+1.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5257604989206000930" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;One thing to note is that the output of &lt;tt&gt;growlnotify&lt;/tt&gt; is being ignored. This is because of a &lt;a href="http://forums.cocoaforge.com/viewtopic.php?f=6&amp;t=14846"&gt;known issue&lt;/a&gt; of invoking &lt;tt&gt;growlnotify&lt;/tt&gt; from &lt;tt&gt;cron&lt;/tt&gt;, whereby the notification still works but the following warning is mailed to you:&lt;br /&gt;&lt;blockquote&gt;&lt;div style="overflow:auto;width:100%;"&gt;&lt;pre&gt;&lt;br /&gt;growlnotify[1592:10b] could not find local GrowlApplicationBridgePathway, falling back to NSDNC&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/blockquote&gt;&lt;br /&gt;I tried using the network settings described &lt;a href="http://forums.cocoaforge.com/viewtopic.php?t=6572"&gt;here&lt;/a&gt;, but this resulted in my notifications not showing up at all. For now, I'm just ignoring the output of &lt;tt&gt;growlnotify&lt;/tt&gt;. I figure if something else goes wrong with it, it'll most likely result in notifications not showing up, which I think I will notice once I start getting used to them.&lt;br /&gt;&lt;br /&gt;One final thing to mention is that I had intermittent trouble with using the &lt;tt&gt;--image&lt;/tt&gt; flag when explicitly running the script. It sounds related to &lt;a href="https://bugs.launchpad.net/growl/+bug/267767"&gt;this problem&lt;/a&gt;, in that the notification would only be displayed intermittently but no other error or warning was emitted. Interestingly, I don't seem to get the problem when the script runs from &lt;tt&gt;cron&lt;/tt&gt;, so I've left the flag in for now.&lt;br /&gt;&lt;br /&gt;So there you go; notifications for uncommitted changes under my home directory, and a great reminder for me to go back and look at whether I want to keep configuration changes that are usually made when my mind is on other things. I've currently got it set to run every 15 minutes, which seems to be a reasonable balance between being too annoying and having too many outstanding changes.&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/6577188874632264829-2966372739943329441?l=kristian-domagala.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kristian-domagala.blogspot.com/feeds/2966372739943329441/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6577188874632264829&amp;postID=2966372739943329441' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6577188874632264829/posts/default/2966372739943329441'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6577188874632264829/posts/default/2966372739943329441'/><link rel='alternate' type='text/html' href='http://kristian-domagala.blogspot.com/2008/10/home-direcotry-version-control.html' title='Home directory version control notification'/><author><name>Kristian Domagala</name><uri>http://www.blogger.com/profile/01334114225292145389</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_TkDxSqrQ5lE/SPbD4bbx9SI/AAAAAAAAAC4/QZlasfESMjA/s72-c/Picture+1.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6577188874632264829.post-8108465434467234477</id><published>2008-10-03T16:31:00.008+10:00</published><updated>2009-03-04T21:43:15.773+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='bash'/><category scheme='http://www.blogger.com/atom/ns#' term='commandline'/><title type='text'>Replacement in Bash parameter expansions</title><content type='html'>I have a few utility scripts to make working on the command line easier. One of them is a shortcut for temporarily getting a file or directory out of the way, by renaming it with a &lt;tt&gt;.bak&lt;/tt&gt; suffix. So instead of typing&lt;blockquote&gt;&lt;pre&gt;mv tmp/foo.txt tmp/foo.txt.bak&lt;/pre&gt;&lt;/blockquote&gt;I can type&lt;blockquote&gt;&lt;pre&gt;&lt;br /&gt;bk tmp/foo.txt&lt;/pre&gt;&lt;/blockquote&gt;and achieve the same thing.&lt;br /&gt;&lt;br /&gt;The script to do this was this simple one-liner&lt;blockquote&gt;&lt;pre&gt;mv $1 "$1.bak"&lt;/pre&gt;&lt;/blockquote&gt;&lt;br /&gt;Unfortunately, due to using tab-completion for file names, I'd often get the following error&lt;blockquote&gt;&lt;pre&gt;bk tmp/bar/&lt;br /&gt;mv: rename tmp/bar/ to tmp/bar/.bak: Invalid argument&lt;/pre&gt;&lt;/blockquote&gt;which is caused by the trailing slash that is included when you tab-complete the directory name. So, ideally, what I wanted to do was check if there was a trailing slash and remove it for the second argument to &lt;tt&gt;mv&lt;/tt&gt;.&lt;br /&gt;&lt;br /&gt;Conveniently, this is easily achieved using a feature of &lt;a href="http://www.gnu.org/software/bash/manual/bashref.html#Shell-Parameter-Expansion"&gt;Bash parameter expansions&lt;/a&gt;:&lt;blockquote&gt;&lt;br /&gt;&lt;em&gt;${parameter/pattern/string}&lt;/em&gt;&lt;br /&gt;The pattern is expanded to produce a pattern just as in filename expansion. Parameter is expanded and the longest match of pattern against its value is replaced with string. If pattern begins with ‘/’, all matches of pattern are replaced with string. Normally only the first match is replaced. If pattern begins with ‘#’, it must match at the beginning of the expanded value of parameter. If pattern begins with ‘%’, it must match at the end of the expanded value of parameter. If string is null, matches of pattern are deleted and the / following pattern may be omitted. If parameter is ‘@’ or ‘*’, the substitution operation is applied to each positional parameter in turn, and the expansion is the resultant list. If parameter is an array variable subscripted with ‘@’ or ‘*’, the substitution operation is applied to each member of the array in turn, and the expansion is the resultant list.&lt;/blockquote&gt;&lt;br /&gt;A quick change to my script and all is well:&lt;blockquote&gt;&lt;pre&gt;mv $1 "${1/%\//}.bak"&lt;/pre&gt;&lt;/blockquote&gt;&lt;br /&gt;Incidentally, calling it with the wrong directory (something like &lt;tt&gt;sudo bk /usr/lib&lt;/tt&gt;) can be a bit disastrous, but that's a different story.&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/6577188874632264829-8108465434467234477?l=kristian-domagala.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kristian-domagala.blogspot.com/feeds/8108465434467234477/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6577188874632264829&amp;postID=8108465434467234477' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6577188874632264829/posts/default/8108465434467234477'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6577188874632264829/posts/default/8108465434467234477'/><link rel='alternate' type='text/html' href='http://kristian-domagala.blogspot.com/2008/10/replacement-in-bash-parameter.html' title='Replacement in Bash parameter expansions'/><author><name>Kristian Domagala</name><uri>http://www.blogger.com/profile/01334114225292145389</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6577188874632264829.post-5265795063496427460</id><published>2008-09-19T10:59:00.009+10:00</published><updated>2008-10-24T09:19:28.157+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='macports'/><category scheme='http://www.blogger.com/atom/ns#' term='install'/><category scheme='http://www.blogger.com/atom/ns#' term='commandline'/><category scheme='http://www.blogger.com/atom/ns#' term='upgrade'/><category scheme='http://www.blogger.com/atom/ns#' term='update'/><title type='text'>Updating MacPorts</title><content type='html'>Hopefully the last time I forget this:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;  sudo port selfupdate&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;I've found that this is the most common fix for a failed &lt;tt&gt;port install&lt;/tt&gt;. For example, today, I had the following error when trying to upgrade Subversion:&lt;br /&gt;&lt;blockquote&gt;&lt;div style="overflow:auto;width:100%;"&gt;&lt;pre&gt;&lt;br /&gt;&gt; sudo port upgrade subversion&lt;br /&gt;---&gt;  Building sqlite3 with target all&lt;br /&gt;Error: Target org.macports.build returned: shell command " cd "/opt/local/var/macports/build/_opt_local_var_macports_sources_rsync.macports.org_release_ports_databases_sqlite3/work/sqlite-3.6.1" &amp;&amp; gnumake all " returned error 1&lt;br /&gt;Command output: sh: line 0: cd: /opt/local/var/macports/build/_opt_local_var_macports_sources_rsync.macports.org_release_ports_databases_sqlite3/work/sqlite-3.6.1: No such file or directory&lt;/pre&gt;&lt;/div&gt;&lt;/blockquote&gt;&lt;br /&gt;Sometimes a &lt;tt&gt;port clean&lt;/tt&gt; is also required.&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/6577188874632264829-5265795063496427460?l=kristian-domagala.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kristian-domagala.blogspot.com/feeds/5265795063496427460/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6577188874632264829&amp;postID=5265795063496427460' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6577188874632264829/posts/default/5265795063496427460'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6577188874632264829/posts/default/5265795063496427460'/><link rel='alternate' type='text/html' href='http://kristian-domagala.blogspot.com/2008/09/updating-macports.html' title='Updating MacPorts'/><author><name>Kristian Domagala</name><uri>http://www.blogger.com/profile/01334114225292145389</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6577188874632264829.post-1824628518291797767</id><published>2008-09-18T13:02:00.009+10:00</published><updated>2008-10-24T09:20:14.242+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='rails'/><category scheme='http://www.blogger.com/atom/ns#' term='scoodi'/><category scheme='http://www.blogger.com/atom/ns#' term='multipart'/><category scheme='http://www.blogger.com/atom/ns#' term='ie6'/><category scheme='http://www.blogger.com/atom/ns#' term='html'/><category scheme='http://www.blogger.com/atom/ns#' term='upload'/><category scheme='http://www.blogger.com/atom/ns#' term='browser'/><title type='text'>Fix for "access denied" problem when submitting background file upload</title><content type='html'>Since &lt;a href="http://www.scoodi.com/"&gt;Scoodi&lt;/a&gt; started to rise in popularity, we've been getting feedback from some Internet Explorer 6 users saying that their photos weren't being uploaded during the process of creating an item. Scoodi uses a common browser &lt;span style="text-decoration:line-through;"&gt;hack&lt;/span&gt; feature to achieve uploading files in the "background", similar to adding attachments in GMail, so you can continue to fill in the form while photos are uploading. The trick involves setting the &lt;tt&gt;target&lt;/tt&gt; of the file upload form to a hidden frame, so that when the form is submitted, the result is sent to the hidden frame instead of having whole page re-displayed with the result.&lt;br /&gt;&lt;br /&gt;Luckily, we were able to reproduce the problem on one of our test machines (though not on another, which made things more &lt;span style="text-decoration:line-through;"&gt;frustrating&lt;/span&gt; interesting). The difference ended up being in the security settings, specifically the "&lt;span style="font-style:italic;"&gt;allow sub-frames to navigate across different domains&lt;/span&gt;" setting.&lt;br /&gt;&lt;br /&gt;To make a long story short, our issue was to do with how we were setting the &lt;tt&gt;src&lt;/tt&gt; attribute on the hidden &lt;tt&gt;iframe&lt;/tt&gt;. When we &lt;a href="http://adams.id.au/blog/2008/05/serving-javascript-using-rails-asset-hosts/"&gt;enabled Asset Hosts&lt;/a&gt;, our source attribute was an absolute path to one of the asset hosts:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;  &amp;lt;iframe ... src="http://asset2.scoodi.com/path/blank.html"&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Going back to the security setting, in our case, it was saying you can't submit a form served from &lt;tt&gt;www.scoodi.com&lt;/tt&gt; to a target frame served from &lt;tt&gt;asset2.scoodi.com&lt;/tt&gt;. When the setting was enforced, it raised an "access denied" error from the line of JavaScript that submits the form.&lt;br /&gt;&lt;br /&gt;Once we worked out the problem, the fix was simple: make sure the &lt;tt&gt;iframe&lt;/tt&gt; &lt;tt&gt;src&lt;/tt&gt; attribute uses the same domain as the page source. In our case, it was as easy as using a path relative to the server:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;  &amp;lt;iframe ... src="/path/blank.html"&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;It was no coincidence that the bug appeared with the increasing number of users to the site, though it wasn't because we were getting a wider range of browsers and configuration permutations. We enabled Asset Hosts because of the increase in users, and when we did that, those IE6 browsers with higher security settings stopped working.&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/6577188874632264829-1824628518291797767?l=kristian-domagala.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kristian-domagala.blogspot.com/feeds/1824628518291797767/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6577188874632264829&amp;postID=1824628518291797767' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6577188874632264829/posts/default/1824628518291797767'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6577188874632264829/posts/default/1824628518291797767'/><link rel='alternate' type='text/html' href='http://kristian-domagala.blogspot.com/2008/09/fix-for-access-denied-problem-when.html' title='Fix for &quot;access denied&quot; problem when submitting background file upload'/><author><name>Kristian Domagala</name><uri>http://www.blogger.com/profile/01334114225292145389</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6577188874632264829.post-7010038105982470239</id><published>2008-08-18T19:48:00.005+10:00</published><updated>2008-10-24T09:20:23.296+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='scoodi'/><title type='text'>Scoodi on TV</title><content type='html'>A couple of weeks ago, I was involved the filming of a "news-fo-tainment" segment where we got to talk about and promote &lt;a href="http://www.scoodi.com/"&gt;Scoodi&lt;/a&gt;, the project I've been involved in for the past few months:&lt;br /&gt;&lt;br /&gt;&lt;object height="344" width="425"&gt;&lt;param name="movie" value="http://www.youtube.com/v/8ZDLVGpOkeo&amp;amp;hl=en&amp;amp;fs=1"&gt;&lt;param name="allowFullScreen" value="true"&gt;&lt;embed src="http://www.youtube.com/v/8ZDLVGpOkeo&amp;amp;hl=en&amp;amp;fs=1" type="application/x-shockwave-flash" allowfullscreen="true" height="344" width="425"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;br /&gt;&lt;br /&gt;The impact that the segment had on the website traffic was a mixed blessing, and it would probably be fair to say that it caught us a little off guard. We've since fixed one of the main bottle necks, and by all accounts, the site is quite stable once again.&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/6577188874632264829-7010038105982470239?l=kristian-domagala.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kristian-domagala.blogspot.com/feeds/7010038105982470239/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6577188874632264829&amp;postID=7010038105982470239' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6577188874632264829/posts/default/7010038105982470239'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6577188874632264829/posts/default/7010038105982470239'/><link rel='alternate' type='text/html' href='http://kristian-domagala.blogspot.com/2008/08/scoodi-on-tv.html' title='Scoodi on TV'/><author><name>Kristian Domagala</name><uri>http://www.blogger.com/profile/01334114225292145389</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6577188874632264829.post-8687464716053276799</id><published>2008-08-07T18:15:00.001+10:00</published><updated>2008-10-24T09:20:32.114+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='fp'/><category scheme='http://www.blogger.com/atom/ns#' term='install'/><category scheme='http://www.blogger.com/atom/ns#' term='haskell'/><category scheme='http://www.blogger.com/atom/ns#' term='mac'/><category scheme='http://www.blogger.com/atom/ns#' term='scala'/><title type='text'>Installing GHC on OSX</title><content type='html'>During my quest to better understand Functors &amp;amp; Monads, it was suggested that I take a detour and learn Haskell first, as I was struggling a bit with Scala's type annotations. So, off to MacPorts I went:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;  ~&gt; sudo port install ghc&lt;br /&gt;  ---&gt;  Fetching ghc&lt;br /&gt;  ---&gt;  Verifying checksum(s) for ghc&lt;br /&gt;  ---&gt;  Extracting ghc&lt;br /&gt;  ---&gt;  Applying patches to ghc&lt;br /&gt;  ---&gt;  Configuring ghc&lt;br /&gt;  ---&gt;  Building ghc with target all&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Half an hour later, I was still waiting for it to build. Something was not quite right. I killed the process and tried again (after issuing a &lt;code&gt;sudo port clean ghc&lt;/code&gt;, because it seemed to be in an inconsistent state after killing it). &lt;br /&gt;&lt;br /&gt;Same problem - it got up to building, then seemed to hang. Looking at &lt;code&gt;top&lt;/code&gt;, I could see &lt;code&gt;ghc-6.8.2&lt;/code&gt; running intermittently. After a while, &lt;code&gt;ghc-6.8.3&lt;/code&gt; was also added to the list of processes (running intermittently), but still no progress on the build.&lt;br /&gt;&lt;br /&gt;I gave it about 45 minutes before killing it again. &lt;a href="http://bradclow.blogspot.com"&gt;Brad&lt;/a&gt; has been down this path before, and he put me on to the pre-packaged installer available from the &lt;a href="http://haskell.org/ghc/download_ghc_683.html#macosxintel"&gt;http://haskell.org/ghc&lt;/a&gt; download page. As per the instructions, I installed XCode off the Leopard disc, then ran the installer, and hey presto, I was &lt;code&gt;ghc&amp;nbsp;hello_world.hs&lt;/code&gt;'ing it up!&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/6577188874632264829-8687464716053276799?l=kristian-domagala.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kristian-domagala.blogspot.com/feeds/8687464716053276799/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6577188874632264829&amp;postID=8687464716053276799' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6577188874632264829/posts/default/8687464716053276799'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6577188874632264829/posts/default/8687464716053276799'/><link rel='alternate' type='text/html' href='http://kristian-domagala.blogspot.com/2008/08/installing-ghc-on-osx_07.html' title='Installing GHC on OSX'/><author><name>Kristian Domagala</name><uri>http://www.blogger.com/profile/01334114225292145389</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6577188874632264829.post-8361777307565192899</id><published>2008-08-04T01:45:00.001+10:00</published><updated>2008-10-24T09:20:59.953+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='install'/><category scheme='http://www.blogger.com/atom/ns#' term='scala'/><title type='text'>Installing/upgrading Scala</title><content type='html'>Because I keep forgetting:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;cd /opt&lt;br /&gt;sudo tar xzf ~/install/scala-2.7.1.final.tgz&lt;br /&gt;sudo rm scala&lt;br /&gt;sudo ln -s scala-2.7.1.final scala&lt;br /&gt;cd scala&lt;br /&gt;sudo bin/sbaz install scala-devel-docs&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;This cryptic message when installing the docs indicates lack of privileges, ie, not running with sudo:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;planning to install: scala-devel-docs/2.7.1.final&lt;br /&gt;Installing...&lt;br /&gt;java.io.FileNotFoundException: /opt/scala-2.7.1.final/meta/cache/scala-devel-docs-2.7.1.final.zip.tmp (No such file or directory)&lt;br /&gt;&lt;/pre&gt;&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/6577188874632264829-8361777307565192899?l=kristian-domagala.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kristian-domagala.blogspot.com/feeds/8361777307565192899/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6577188874632264829&amp;postID=8361777307565192899' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6577188874632264829/posts/default/8361777307565192899'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6577188874632264829/posts/default/8361777307565192899'/><link rel='alternate' type='text/html' href='http://kristian-domagala.blogspot.com/2008/08/installingupgrading-scala.html' title='Installing/upgrading Scala'/><author><name>Kristian Domagala</name><uri>http://www.blogger.com/profile/01334114225292145389</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6577188874632264829.post-6574400637757109814</id><published>2008-06-30T20:52:00.001+10:00</published><updated>2008-10-24T09:21:05.819+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='split'/><category scheme='http://www.blogger.com/atom/ns#' term='example'/><category scheme='http://www.blogger.com/atom/ns#' term='commandline'/><title type='text'>Splitting up large files</title><content type='html'>This is one of those things that I need to do occasionally, but not often enough that I've been able to commit it to memory.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; split -b 4000m large_file large_file.&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;This will split a the large_file file into 4Gb files with filenames &lt;code&gt;large_file.aa&lt;/code&gt;, &lt;code&gt;large_file.ab&lt;/code&gt;, etc. Before doing this, it really helps to make sure you've got enough space for the new files - ie, at least as much free space as the file you are splitting!&lt;br /&gt;&lt;br /&gt;To get the parts back together:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; cat large_file.* &gt; large_file&lt;br /&gt;&lt;/pre&gt;&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/6577188874632264829-6574400637757109814?l=kristian-domagala.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kristian-domagala.blogspot.com/feeds/6574400637757109814/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6577188874632264829&amp;postID=6574400637757109814' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6577188874632264829/posts/default/6574400637757109814'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6577188874632264829/posts/default/6574400637757109814'/><link rel='alternate' type='text/html' href='http://kristian-domagala.blogspot.com/2008/06/splitting-up-large-files.html' title='Splitting up large files'/><author><name>Kristian Domagala</name><uri>http://www.blogger.com/profile/01334114225292145389</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6577188874632264829.post-5398791158759983769</id><published>2008-06-17T17:36:00.001+10:00</published><updated>2008-10-24T09:21:10.591+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='scm'/><category scheme='http://www.blogger.com/atom/ns#' term='mercurial'/><category scheme='http://www.blogger.com/atom/ns#' term='git'/><category scheme='http://www.blogger.com/atom/ns#' term='subversion'/><category scheme='http://www.blogger.com/atom/ns#' term='vcs'/><title type='text'>Solving The Tangled Working Copy Problem</title><content type='html'>I just read &lt;a href="http://tomayko.com/writings/the-thing-about-git"&gt;this article&lt;/a&gt;, which  goes into great (as in good) detail about one way to solve the problem where you have more than one conceptual change in your work-space, and you want to physically separate them into different groups.&lt;br /&gt;&lt;br /&gt;When I've encountered this problem previously, I've generally just backed up the working copy, reverted the unwanted changes in the working copy, submitted it, then pulled back the additional changes form the backup. But the way described in the article is a much better way!&lt;br /&gt;&lt;br /&gt;Apparently it is supported in Mercurial, so I'll have to give it a go next time. Unfortunately, it doesn't help when I'm working with Subversion, as is currently the case at work. However, the article also mentions a way of do a similar thing using the patch program, which is still better than my manual way around it.&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/6577188874632264829-5398791158759983769?l=kristian-domagala.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kristian-domagala.blogspot.com/feeds/5398791158759983769/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6577188874632264829&amp;postID=5398791158759983769' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6577188874632264829/posts/default/5398791158759983769'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6577188874632264829/posts/default/5398791158759983769'/><link rel='alternate' type='text/html' href='http://kristian-domagala.blogspot.com/2008/06/solving-tangled-working-copy-problem.html' title='Solving The Tangled Working Copy Problem'/><author><name>Kristian Domagala</name><uri>http://www.blogger.com/profile/01334114225292145389</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry></feed>
