Friday, December 31, 2010

So long 2010...we hardly knew ye

Happy new year to all :)

I guess it is one of the few holidays that spans all cultures (although when you consider the new year begins or what year it is may differ).  For me, New Years has always been bitter sweet, because I do always think of 'auld lang syne' (days of the past).

As  a buddhist, I try to be grounded in the present, but it is hard not to think of the past.  I definitely think I look back more than I look forward.  My first guess would be that the past is a more happy place, but I'm not sure about that.  Yes, there were good times, but they were definitely more memorable.  That has good and bad connotations.

There is an old zen saying; "If you seek it, you shall not find it".  People, including myself, are constantly searching for something.  Perhaps it is a longing for the past with old friends to relive old times.  Or perhaps people are seeking to find a mate, or a better job in order to find happiness.  What people rarely do however is just see what they have now.  More importantly, people don't question why they are even seeking.

New Years day is supposed to be about looking to the future, and changing for the better...while saying goodbye to what was.  Perhaps the greatest mystery to me about Buddhism is that I supposedly am already enlightened, there is nothing for me to gain.  At the same time, attachments should be abandoned, but it is not the same as saying goodbye to the past.

I remember a few years ago, I told one of best friends that you could sum up Buddhism in two words: "let go".  But how we let go is important.  If we let go or say goodbye with sadness....we truly haven't let it go.  It remains in our hearts.  When we let something go, we have to understand down to our bones that whatever it is we are letting go was never ours to begin with.  Everything we have, and everything we are is a gift on loan. It comes, and one day it goes.  Indeed, I came up with the name Sojourner (a temporary visitor or traveler) as an acknowledgment to this truth.

Although I understand this intellectually, I have not felt it to my core.  A part of me still holds on.  And the irony is that I can see that by holding on to things, it is why I suffer.  And yet I hold on to it all the same.  There is comfort to holding on to things.  Sometimes there is even comfort in ache, longing or melancholy.  It centers ourselves...or so we think.

I would say that I will resolve to be a better Buddhist this year, but I know the danger in that.  Things must come naturally.  Discipline can only go so far, and after awhile is actually a detriment.  It is the same with anything that is forced.  Repressing things is bad, because the desire is still there.  But without courage, change can not happen.  So although I hope that I can change, I know that what will happen will happen.

Thursday, December 30, 2010

Laziness is hard work

UPDATE 2:
I was re-reading a bit of Stuart Halloway's book "Programming Clojure", and he states that the repl is NOT lazy.  If for example you create a lazy sequence, you should store it in a var if you are at the repl, otherwise the repl will eagerly attempt to evalute everything.  This is why the code WITHOUT being wrapped by dorun works in the repl, but not as a standalone program.


UPDATE:
Interstingly, while the code snippets below work at the repl as-is, if you run them as a program they will not.  What is most interesting is that I didn't think the code below would work, which is why I was mildly surprised it did.  The title of the post came from the fact that I thought making calls in these lazy sequences wouldn't work.

If you do the code below, then you will have to wrap your code in  dorun macro.  This forces the evaluation of functions with side effects (which these do), and thus will allow it to work.

I tried a few things in my clojure code, thinking that it would make my code cleaner.  Although the doto macro is nice, it still is a lot of boilerplate...

(doto button-group
   (.add (JRadioButton. "One"))
   (.add (JRadioButton. "Two"))
   (.add (JRadioButton. "Three")))

ooooh, I got to leave out button-group in all the function calls....that's still not exactly easy on the fingers.  But you'll see code like that in a lot of other tutorials or sites.  So I thought, why not call map on a collection instead?


(def rdo-btns
  (map #(.add button-group %1) [ (JRadioButton. "One")
                                                    (JRadioButton. "Two")
                                                    (JRadioButton. "Three") ]))

This will work, but remember that it only works because of side-effects.  The call .add is doing something to button-group and is in effect changing the state of button-group.  In a pure function, this wouldn't be the case. One might argue that this is actually slightly longer, but it has the advantage that rdo-btns now contains a sequence of the JRadioButtons, while the first example above would require extracting the JRadioButton from button-group.

Another possibility is to use a for sequence comprehension like so:

(def rdo-btns
  (for [ rdo [ (JRadioButton. "One") (JRadioButton. "Two") (JRadioButton. "Three") ] ] (.add jpanel rdo)))

This will also return a sequence like map will, and again, it only works because of side effects.  Nevertheless, since we're working with java classes, that's bound to happen.  So it might be better to put asterisks around the symbols like *jpanel* or *button-group* to indicate a symbol with mutating state.

Wednesday, December 29, 2010

Frustrating swing...DocumentEvent

I spent a good 2 hours trying to figure out why after I clicked on the Browse button what I expected to happen wasn't happening.  Clicking on the Browse button calls up a JFileChooser dialog.  Once the user selects the desired directory or file and clicks the Ok button, this will set the text of the same row's JTextField.  However, the same text wasn't showing in the Command row JTextField which it should have.

The strange thing is that typing in the field belonging to any of the first 3 rows WILL update the text in the fourth (which I call the command row, since it belongs to a map like {:command {:label lbl :field fld :button btn}}).  So my suspicion is that filling in the text via calling the JTextField.setText function did NOT fire an event that the DocumentListener was listening for.

I was correct and learned that setText is not a bound property and thus doesn't trigger event.  I then learned that I needed to make a change to the JTextField's underlying Document to trigger an event that insertUpdate would be called on.  I tried doing this, and my code now looks like this:



  36 ;; Create a proxy for clicking on the Browse button
  37 (defn on-click 
  38   "Returns a proxy handler for a given button"
  39   [ field ]
  40   ;; closures are cool. 
  41   (proxy [ActionListener] []
  42     (actionPerformed [ event ]
  43       (let [text (.getText field) 
  44             selection (get-file-selection) 
  45             fld-doc (.getDocument field)
  46             fld-len (.getLength fld-doc)]
  47         (if (empty? text) 
  48           (.insertString fld-doc 0 selection nil)
  49           (let [ tx (apply str text ":" selection) ]
  50             (doto fld-doc
  51               (.remove 0 fld-len)
  52               (.insertString 0 tx nil))))))))  
  53 
  54 (defn set-fld 
  55   [ field fld-string ]
  56   (.setText field fld-string))
  57 
  58 
  59 ;; When any of the textfields (except the cmd-fld) changes, we
  60 ;; need to add those changes to cmd-fld.  cmd-fld should always
  61 ;; hold the concatenation of: ext-jar row's fld, classpath fld
  62 ;; and clojars fld
  63 (defn cp-string [ src flds ]
  64   (if (.isFocusOwner src)
  65     (let [ ext-jar-txt (.getText (flds :ext-jar-row))
  66            cp-txt (.getText (flds :classpath-row))
  67            clj-txt (.getText (flds :clojars-row))
  68            cmd-fld (flds :cmd-row)
  69            all-flds (str-join ":" [ext-jar-txt cp-txt clj-txt])]
  70       (println "external jar = " ext-jar-txt)
  71       (println "classpath = "cp-txt)
  72       (println "clojars = " clj-txt)
  73       (set-fld cmd-fld (str "java -cp " all-flds)))))
  74 
  75 
  76 ;; We need a proxy that will be a TextHandler for the cmd-fld.
  77 ;; As text is entered into any of the first three rows (either
  78 ;; manually or via the FileChooser), the command JTextField
  79 ;; should reflect those changes 
  80 (defn text-handler
  81   "Returns a proxy for a given JTextField"
  82   [ src txt-flds ]
  83   (.. src getDocument 
  84     (addDocumentListener 
  85       (proxy [DocumentListener] []
  86         (insertUpdate [e] (cp-string src txt-flds))
  87         (removeUpdate [e] (cp-string src txt-flds))
  88         (changedUpdate [e] (cp-string src txt-flds))))))


The insertString is supposed to alter the Document object which in turn should fire a DocumentEvent.  So the basic flow is like this:

1.  user selects file
2.  this causes actionPerformed to be called
3.  this causes the JTextField Document to change
4.  this should cause a DocumentEvent to be fired
5.  if that happened, insertUpdate should be called from the DocumentListener
6. which would call cp-string to concatenate all the JTextFields and return the result in the command JTextField

I know the DocumentListener works, because if you manually type into the field...the command row's JTextField immediately updates with whatever is typed in.  So I'm not sure what I'm doing wrong here.

Here's the latest screenshot:

Sunday, December 26, 2010

Need to learn more swing now

So, I finally got my little clojure launcher cleaned up and able to look for insertUpdates or removeUpdates.  Unfortunately, I now need to implement  property change listener, because when you select the browse button and choose your directory or file, although the associated JTextField gets populated with the correct string, this new string is not reflected in the command row's JTextField.  Calling setText on a JTextField apparently does not trigger an event that insertUpdate listens for.

But anyhow, here is the latest screenshot:










As you type into any of the top three fields, the command row gets updated.  I still need to put in the actual beginning of the command....eg "java -cp ... -jar somejar.jar"

Once that's done, I need to execute a new process, and tie in its stdin and stdout to  JTextArea component.  I also need to make it so that you can save these fields and store them away for future use.  I am thinking of saving them as records in a database, this way you can retrieve commonly used values.  I will also have the means to write them to a file.

The code was also significantly cleaned up.  I didn't like how I was using a top-level def for the JPanel and JFrame, and I also started going down the path of a global ref called rows which was a map containing the rows in the panel.  This just got uglier and uglier, so I decided to make all these things local symbols in the -main function instead.

I solved the mutability problem with a map I wanted to update by creating the following function:


(defn into-map
  "This takes a list or vector of keys and a list or vector of values and
   makes a map out of it"
  [ init key-coll val-coll ]
  (into init (map #(assoc init %1 %2) key-coll val-coll)))

So for example, you could call it like this:

(def rows (into-map {} [:row1 :row2 :row3] [(JLabel. "First") (JLabel. "Second") (JLabel. "Third")]))
=> {:row 1 #<JLabel ...> , :row2 #<JLabel ...> , :row3 #<JLabel ... > }

It's sort of similar to hash-map, but instead of k v, k1 v1, ... pairs as arguments, all the keys are in one collection, and all corresponding values are in another vector.


So I'm slowly getting the hang of this.  I find functional programming much more intellectually stimulating than imperative style programming.  One of the reasons my code is often buggy is from one of three following reasons:

1.  Off by one error in some for loop
2.  Failed to consider some code path in a function with multiple returns or exception possibilities
3.  Bogus while loop conditional checking (usually with some sentinel value)

But so far in my clojure code, I rarely have to deal with this if at all. It's far more interesting to think recursively or how the output of one function can be used as the input of another.

Better to keep your mouth shut....

Mark Twain once said, "Better to keep your mouth shut and appear stupid, than to open it and remove all doubt".  I have been hesitant to write a technical blog or release an open-source project for fear of looking stupid.  After all, potential employers could one day look at my blog and think, "good lord, this guy doesn't know what he's talking about".

I have to admit that my blogs are more like breadcrumbs than anything else.  If someone happens to learn from my mistakes, more the better.  I don't consider myself a particularly good software engineer.  I know many people who can come up with nicer algorithms, can code faster, and code more elegantly than I.  What I do have however that is better than your average programmer (with just  bachelors degree) is curiousity and a willingness to communicate.

I have met some very smart people who lack curiousity.  Once they know a way to solve something, they are done.  I've never understood that.  To me, discovery never ends.  Because things always change, our understanding always has to change.  I have also met brilliant engineers who are, to put it bluntly nice real world examples of the stereotypical anti-social (or non-social) engineer.  It's amazing how few engineers will say what's truly on their mind to management.  Or how little two different groups (say between Test and Development) will talk to each other.  While many engineers may come up with faster, more elegant or less buggy solutions than I do, I somehow often seem to be the one that Management comes up to, even when there are more senior engineers around.  And these managers aren't always your PHB type, they are often technical themselves.

Since I enjoy learning, and I'm not afraid to speak my mind (even when I am wrong, though I try to warn people when I am not sure of my answer), I thought it was high time to make a technical blog.  Engineers care about two things: correctness and practicality.  They are not moved by pretty talk, appeals to emotion or power, or many other things that non-engineers or non-scientists care about.  If your help isn't correct, and it's not pragmatic, a technical person will tune you out.

So although my solutions here may not be perfect, I hope readers will understand that this blog is less about giving answers as it is about asking questions.  That's another area I have noted I am better than average at.  I remember a quote from Pablo Picasso.  He said:

Computers are worthless.  All they can do is give you answers.

A good teacher doesn't just help a student arrive at a way to solve a problem, but he also stokes the fires of curiousity.  Since I am a curious person, I hope that rubs off on others, even if my blog posts reveal that I DONT know how to solve a problem.

Thinking about state is hard

I'm finally getting the hang of clojure syntax, but I'm still having trouble living in its immutable world.  I understand the idea that functions take inputs and yield outputs, but I'm still trying to stop thinking that some data structure I need is itself changed by a function.  It's not different really than something like this:

y = 10


def changeVar(x):
    x = 20
    return x


print "Output of function = ", changeVar(y), " Value of y is still ", y


y = 20
print "Now y = ", y

Which of course would print:
Output of function = 20 Value of y is still 10
Now y = 20


However, this is a trivial example.  The reason the function changeVar() doesn't change the value of y is because the local variable x is in effect a different variable (it has a lexical binding local to the function, as opposed to the global variable y).  In clojure, with a few exceptions, EVERYTHING is immutable.  Once some symbol is bound to a variable, that's its value forever more unless you have made it a ref, agent, atom or var (though you can shadow a global symbol with a local one).

To give you a more concrete example of something troubling me, I wanted to create a map of various swing components I have created.  I created a function called make-row-fn which builds three swing components: a JLabel, a JTextField, and a JButton.  Each of these three components are then added to a JPanel object.  Instead of getting components via JPanel's getComponent() method, I would rather have these components readily available in a map...for example:

(make-row  [ jpanel label-string button-string ]
   (let [ lbl (JLabel. label-string)
           fld (JTextField. 15)
           btn (JButton. button-string) ]
      (doto jpanel
        (.add lbl)
        (.add fld)
        (,add btn)
       {:label lbl :field fld :button btn} )))

(def components {} )
(doto components
  (assoc  :ext-jar-row (make-row "External Jars" "Browse"))
  (assoc :classpath-row (make-row "Classpath Dir" "Browse"))
  (assoc :clojars (make-row "Clojure files" "Browse")))


If you don't see why this won't work, consider what is happening to the components map on each assoc call.  The map components starts empty.  So the first call to assoc will yield:

{:ext-jar-row {:label lbl  :field fld  :button btn}}

On the second call to assoc, you might think components would equal the following:
{:ext-jar-row    {:label lbl  :field fld  :button btn}
 :classpath-row {:label lbl  :field fld  :button btn}}

In languages with mutable hashes/maps/dictionaries, this would be true.  But remember, Clojure returns a NEW map with the value of the original input having an added key-value pair you specified.  So instead, on the second call, the returned dictionary would be:

{ :classpath-row{:label lbl  :field fld  :button btn}}


Worse, components itself is still empty.  So how do you make each assoc call (or any function that returns something you want appended to it) make the original?  One answer is to loop through with recursion and rebind components on each loop.  Another (potential) answer is to use (comp) to compose the functions.  For example I could do this manually:

(assoc
  (assoc
    (assoc components :ext-jar-row  (make-row ...)) :classpath-row (make-row ...) ...)

If you look at that, it obviously looks recursive.  But can you see that it's also a composition of functions?  If not, remember what a composition is in mathematical terms.  If I have two functions:

x = g(h)
y= f(x)

Then I could compose the two like y = f(g(h))

Basically the output of one function is the input of another.  What happened above with the nested assoc calls is in essence a composition.  Earlier, I said that (comp) was a potential solution.  Unfortunately, I have not figured out how to use comp on complex functions.  The call to assoc takes 3 args, the map to associate to, a key and a value.  So I tried this...

(def nested-assoc (comp assoc assoc assoc)) ; a three deep composition of assoc

But how do I use nested-assoc?  That's what I haven't figured out how to do yet.  So for the time being, I'll use a loop/recur instead.  I'm not positive I can use comp, since it appears from the doc that although one of the functions can take variable args, it says the result of the rightmost composed function is fed to the next (more left) function.  This seems to imply that any function other than the rightmost can only take one arg.  Hmm, perhaps I can make this work with partial functions...since I know all the values of my args except the map itself.

Unfortunately, I have also realized two other things about clojure.  The first is what I related to above...namely that trying to model a problem without mutating state is still something I'm grappling with.  My code has too many global symbols I think, and perhaps I am still thinking too imperatively.  This might also be because I am writing Swing GUI code which heavily relies on Java, which in turn means I'm bringing a lot of Java baggage with me.  I wish there was more Clojure swing code I could look at.  Stuart Sierra's blog on mixing clojure and swing has been tremendously helpful, but as is usual with most tutorials or blogs, once things get complex, the examples aren't all that fruitful anymore.

The second problem is related to the first.  I think clojure needs more "native" clojure libraries.  I know one of the reasons behind the design of clojure was that it is supposed to be pragmatic.  One of the pragmatic choices of clojure is that it can leverage all the existing java libraries already out there.  The problem with this however is that you also bring all the ills of Java with you....mutating state, the need to use proxy to implement abstract classes or interfaces, etc.  I think some people in the clojure community might not like the idea of reimplementing something that already exists in Java....then again, many things already have been ported to pure clojure (the xml libraries come to mind).

Clojure is still a very young language, and I hope it gets more support to build the infrastructure it needs to be even more prosperous.  I really think that more people would be willing to use it if people didn't think it was so hard.  I think one of the reasons it seems that Scala has more momentum is that it seems more familiar.  It only dips its toe into functional waters.  I think Scala is shooting itself in the foot with its hybrid approach.  On the one hand, the learning curve is easier, because people learning it can only use the functional aspects as they need it.  This will create some Scala code that is heavily functional, and some that is heavily OO, and some that are a hybrid.  If you don't know all paradigms, some Scala code may appear very foreign.

In fact, I see in Scala the beginnings of the things I hate about perl.  Now admittedly, I've hardly written any Scala code (I only got to chapter 10 in the Programming Scala book by Odersky before I abandoned it for Clojure), but I already saw how some things were optional and there were different ways to do the same thing.  This "There Is More Than One Way To Do It" (TIMTOWTDI) is in my humble opinion a horrible approach when trying to learn a language.  The problem is compounded when you have not only different syntax to do the exact same thing, but you have more than one paradigm to program in.  However, I do like Scala's pattern matching and traits, and Scala has shown that you can have immutable objects (where I think they went wrong is that Scala enforces functional paradigm by convention rather than force...immutable state via var's are just as first class as immutable data via val's).

"But you like python!! That's a multi-paradigm language!".  This is true, but python's syntax is very simple compared to Scala (and there's preferably only one way to do it).  Also, python's functional roots are somewhat weak: lambdas have limitations, python has no concept of immutable data (and no, strings don't count...you can't make a class final, or define a variable as a constant).  So although python does have full closures (just not good anonymous functions), and you can declare, return and pass in functions (or classes) as first class citizens, many other things just aren't all that functional.  Of the python code I have seen, very little of it has ever looked functional other than the occasional lambda, passing in of a function as a callback, or having a class implement __callable__.  Scala on the other hand bills itself as a functional language, and many have taken issue with this.

Moreover, Scala will have the same "issue" with Java that clojure does.  Namely that if Scala is written in a functional style, it will have the same interoperability issues.  Of course Scala code IS Java code (just like clojure code IS java code), but that doesn't mean that they will play nicely.  However, because Scala is a hybrid language, I surmise that it can interoperate with Java more seamlessly than Clojure can, and this is probably another reason for its greater uptake (so far).

So I think the harder part to learning clojure isn't the lisp-y syntax, it's the functional paradigm.  Honestly, getting used to s-expression syntax isn't that bad, and clojure is much nicer thanks to the [] and {} notation.  But I'm still struggling with the functional side, though I think that's just a matter of time.  I remember when I first started learning LabView, a dataflow oriented language, I had a really hard time understand the code flow.  Unlike non data-flow languages, data flow languages (like VHDL) execute when inputs are valid.  So data flow languages excel at visualizing and implementing parallelization.  The order in which functions are executed isn't based on a top-to-bottom writing of the code, nor left to right (LabView is a "graphical" language where you connect nodes/functions via wires, and the wires represent inputs and outputs).  Eventually, I kind of got it, but it took several months.

When I hear people say, "once you know one language, it's easy to pick up any others", I know they haven't learned that many languages.  To make an analogy with spoken languages, once you know one romance language, it's not hard to pick up others.  Italian is similiar enough to Spanish which is similar enough to Portuguese which is similar enough French...etc etc.  And English, though a Germanic language, also has a lot of borrowed French words (thanks to the Norman conquest of England), so it's not too hard for English speakers to pick up on romance languages.  But to go from English to Chinese?  Not only is the alphabet totally different, it's a tonal language (which English has no comparison to).

The functional paradigm is quite a bit different than the imperative model.  When you go from  C++ to Java to python to perl to ruby, you're pretty much staying in the imperative and object oriented world.  Although clojure is my first and only language, I can see that it picked up a lot from Haskell (laziness, STM, functional paradigm) which kind of makes clojure a love child of lisp and haskell (or maybe scheme and haskell?).  But I can say that learning lisp has been an interesting challenge.

Wednesday, December 22, 2010

My first open source project

Well, I finally did it.  I actually have a project that's hosted on https://bitbucket.org/Dauntless/sojourner (see my links to the left)

I decided to put up the work I've been doing on my clojure project there.  Eventually I will probably move it to github, but I know at least some of mercurial, while the only thing I know about git is how to clone something.  Unfortunately I don't think bitbucket has a good open-source plan like github does (hmmm, maybe that's why git is wining the DCVS contest).

Basically this project is first and foremost a learning project for me on many levels.  I've never done an open source project before...not even as a commiter.  Secondly, this will help me learn clojure.  Thirdly, it will hopefully have at least some practical value.  And finally, I wish to document this very well so that others can also learn from it.

This project has one major philosophical mantra:
1.  If it's not documented, it's a bug

I'm not just talking about API documentation either.  I like projects that have high level guides, tutorials or other documentation.  I find most API documentation next to useless (and I will point my finger here at clojure itself).  I will take a project that has less features but better documentation than a project with more features but little documentation.  It's a sad fact that most open source projects have poor docs.

I would also like the project to follow a test driven development philosophy, but honestly, I'm not sure how I am going to do this for a gui program (selenium?).  I also have to be honest and say that I still haven't yet wrapped my head around TDD despite being  Test Automation Engineer.  TDD makes sense when your API is already solidified, and therefore you have a spec to test against.  But how do you create tests when you are still exploring and shaping up the API?

Nevertheless I am stoked on this.  Even if no one else uses it, it is still a great learning tool for me.

What do employers want?

I have pretty much had to teach myself everything I have for the last 2 years.  I taught myself perl (though not willingly).  I did get to go to some SAS and Sata training classes, but I had to actually learn how to send SCSI, SATA or SMP commands by myself (admittedly, by looking at other people's code).

I also taught myself the basics of SQL...just enough DDL to create some tables with constraints, and some simple queries (including inner joins) and enough inserts to populate the various tables.  This included figuring out JDBC (through jython and java) and how to work with the result sets they returned.  And speaking of jython, I had to figure out the differences between jython and python.  I also had to learn a tiny bit about java servlets as I used jetty for my test http server to serve up a jnlp file.  Learning the basics of maven came in real handy for this because not only did it do the verification and creation of the signed jars, it also launched the jetty server in my maven project.

I also taught myself a big portion of the more advanced uses of python, including lambdas, implementing some of the "magic methods", or using ctypes to call into shared C libraries instead of using the black box that is SWIG.  I also wrote a proto-type GUI using wxPython that had a built in pyshell (so that any element of the gui could be modified or read from the shell itself....python introspection rocks!).  It was in all my python work that I finally became comfortable with recursion.   And because I've been doing more python work, I got interested in the mercurial SCM (although I appear to have picked the losing horse in the DCVS game since git appears to be winning more and more converts).  And using Sphinx for documentation is really nice.

Right now, I am in the process of learning Eclipse plugins.  This by necessity also means that I have to understand SWT and OSGi.  I have so far written some really basic plugins, with the most advanced one being a stand-alone tree view that using JFace (unfortunately.....Eclipse is by far the worst documented gui toolkit/framework I have seen, and I have written modest GUIs in swing, wxWidgets, wxPython, and Qt).  Given that I consider myself a mediocre Java programmer at best, I consider it pretty amazing that I have gotten so far so fast.

The common theme running here is that I am self-taught.  For all the examples above save learning SQL, none of my co-workers helped me.  I am not afraid to learn and in fact I enjoy learning new things.  I have discovered that this is a rare trait.  Heck, I even taught myself the basics of C++ before I went to school.  So while I consider this a valuable trait, I often get the feeling this isn't what employers want.

My feeling from reading job postings is that they don't want someone who is teachable or trainable....they want someone who already has (some expert level in) some skill.  While to some extent I can understand this if they want a team lead or senior position, I don't understand this for ALL positions.  In my own opinion, some one who has shown that they can learn is more valuable than someone who has lots of experience in one thing.

Why?  Because someone who knows only one or two things really well hasn't proved that they can think in different terms.  One thing that learning multiple languages has taught me is that there are different ways to model or solve a problem.  When I first started learning python, I had a hard time wrapping my head around the fact that variables weren't typed.  When I started learning XML, I started making all config files xml files.  But when I started learning databases, I started thinking in terms of getting results from a database.  When I learned OOP languages like C++ and Java, I thought all solutions had to belong to classes (the kingdom of nouns), but as I started learning clojure, I realized that types and polymorphism didn't have to be object oriented.

Is it nice to know RabbitMQ or Selenium or Wicket or ActiveRecord...blah blah blah?  Sure.  But I think it's more important to find someone who can pick up anything new.  Someone who could write device drivers, write back end web server apps, find patterns from a database, write thick client GUIs, and everything in between.  Then again, maybe that's just me.  I am a jack of all trades, master of none....but that's how I like it.

Tuesday, December 21, 2010

Clojure Launcher pt. 2; now with ActionListeners!

I finally got a chance to work some more on the Clojure launcher GUI program.  I refactored a lot of the code and decided to make use of some closures.  When I started looking at my code, it actually seemed like a macro might be more useful, and I'll explain why I think so in a little bit.

But here so far is my new code.

   1 (ns sojourner.gui
   2   (:import (javax.swing JPanel JButton JLabel JFrame JTextField JFileChooser)
   3            (java.awt.event ActionListener)
   4            (net.miginfocom.swing MigLayout)))
   5 
   6 (def jpanel (JPanel. (MigLayout.)))
   7 
   8 ; Create a file chooser that will pop-up if the user clicks
   9 ; on any of the Browse buttons
  10 (def fc (JFileChooser.))
  11 
  12 ;; This is the function that will be called when any of the Browse buttons are clicked
  13 ;; Basically, we open up a JFileChooser dialog, and we capture the file/directory
  14 ;; that the user selects.  We then append this to the JTextField
  15 (defn get-file-selection [ ]
  16     (let [ fc (JFileChooser.) 
  17            retval (.showOpenDialog fc nil) ]
  18        (if (= retval JFileChooser/APPROVE_OPTION)
  19           (do 
  20              (println (.getSelectedFile fc))
  21              (.getSelectedFile fc))
  22            "")))
  23 
  24 ; Create a proxy for clicking on the Browse button
  25 (def on-click (proxy [ActionListener] []
  26                 (actionPerformed [ event ] (get-file-selection))))
  27                     
  28 
  29 (defn make-row-fn 
  30     [ panel lbl-string fld-string btn-string ]
  31     (fn [ panel ]
  32       (let [btn (JButton. btn-string) ]
  33          (.addActionListener btn on-click)
  34          (doto panel
  35            (.add (JLabel. lbl-string))
  36            (.add (JTextField. fld-string 10))
  37            (.add btn "wrap" ) ) ) ) )
  38 
  39 ;; It seems to me that all these make-row functions could be encapsulated
  40 ;; inside of a macro, or at the least, return a function which does the following
  41 (def make-ext-jar-row (make-row-fn jpanel "External Jars" "" "Browse"))
  42 (def make-classpath-row (make-row-fn jpanel "Class path" "" "Browse"))
  43 (def make-clojars-row (make-row-fn jpanel "Clojure files" "" "Browse"))
  44 
  45 
  46 (defn make-launcher [ panel ]
  47    ( let [p (doto panel
  48              (make-ext-jar-row )
  49              (make-classpath-row )
  50              (make-clojars-row )) ]
  51      ; return the frame after we're done here
  52      (doto (JFrame. "Java Launcher")
  53        (.setContentPane p)
  54        (.setSize 300 150)
  55        (.setVisible true))))
  56 
  57 (def frame (make-launcher jpanel))
  58 
  59  
 
 And this is what it looks like


Yeah I know, it's not a lot to look at, but now if you click the Browse button, a JFileChooser dialog will appear. However, there's still a lot to do:

1. Get the file selected, and enter it in the corresponding JTextField
2. Rework the make-row-fn as a macro, so that each button can have a different proxy
3. I'm going to rework this to use leiningen (clojure's version of maven)
4. A new JTextArea which will contain either the repl launched or the running program
5. Some fields to enter the jar or main to run (eg java -jar myjar.jar)

 

Back to the basics; algorithm analysis

For some reason, my mind has been mush all day, so I didn't get to work on the Clojure launcher like I wanted.  Late yesterday, I also bought the book Python Algorithms by Magnus Lie Hetland, and I could only half-heartedly read through the first chapter today.

Nevertheless, I really want to get back to CS basics.  For the first two years out of college, I didn't really use any of my training I used in school.  Only once did I start to work on a C-based xml parser, but I left shortly thereafter and never got a chance to flesh it out.  What did the xml parser have anything to do with what I learned in school?

Ironically, it had a lot to do with something else I've done recently.  In both cases, I needed to implement a depth-first search algorithm (and data structure).  I recently had need of creating a software dependency manager.  We have many tools, scripts, programs, frameworks and libraries which have dependencies on other tools, scripts, programs, frameworks or libraries.  It dawned on me one day that this transitive dependency list was really just a tree structure, and I could safely install some 'artifact' if that artifact had no children (it was a leaf node).  So once I figured out these dependencies were a tree, I then had to come up with a depth-first search algorithm to find an artifact with no children.  The recursion would then pop-off the stack and I would be back to the parent.  If the parent then had no more children, it too could be installed, otherwise I descended down the child branch of the parent.

Surprisingly, in school, we didn't cover depth first or breadth first searches in our Analysis of Algorithms class.  Instead, we covered these in an introductory AI course.  My recollection of my Analysis of Algorithms class was that I did fairly well in it, but honestly, many of the algorithms were just something I memorized.  Sure, I understood some of the basic principles, like divide and conquer for search algorithms, or 'greed is good' for certain other algorithms, or how memoization could save computational cycles.  But many of the algorithms just seemed like something to memorize and they never really sank in (to this day, I still don't conceptually understand how quick sort works, though I can tell you that on average it has the best average search time, though the worst worst case search time if the items are already sorted).

One problem when you are going through school is that in many ways, you are still struggling to master the programming language, so you can't really concentrate on the essence of the problem at hand.  My belief is that simpler languages should be used to teach the concepts (like python or ruby), while using C or C++ to get students used to the idea of pointers, the difference between the stack and the heap, and generally a better view of how the machine itself actually functions.  I'm NOT a believer that students should only learn C# and/or Java (especially without some kind of introductory microcontroller class that teaches assembly) because otherwise students will never truly appreciate how operating systems and drivers work.

That being said, trying to learn how to heapify some data structure while still struggling with how pointers work is not a good combo.  Now that I'm more confident with actual programming languages, I'd like to go back and revisit some of the courses I took in school, and hopefully I can pay more attention this time around.

Another pet Clojure project I'd like to work on is to create a multi-threaded merge sort function.  It seems to me that because the dividing up of the sequence into halves requires no synchronization, this should be feasible.  If you think about the problem, every split could be done by a new thread.  It's the recombining part that I'm not sure about.

One thing I am curious though about calculating the runtime efficiency of an algorithm is whether they take into account parallelism.  As far as I can remember, only one thread of execution was implied.  But if you can create an algorithm that can be worked on in parallel, then obviously, the runtime efficiency should be better.  I do not see why several of the divide-and-conquer sorting algorithms could not be faster than quick sort (IIRC, as far as I understood quick-sort...which isn't well....it seemed to me that the whole pivot point thing couldn't be parallelized).  But most of the divide and conqueror algorithms (merge-sort, heap-sort for example) should be able to take advantage of multiple threads or processes of execution.