This blog has served me well for the past three years still iv decided to give it a new home that iv developed, eating my own dog food.
Since Iv developed the entire thing I believe that the reading experience will be better & more interesting to you all, all the old content has been migrated, ill redirect to the new one.
Looking forward to meet you there!
Development for the masses
A blog about software development and other software related matters
Blog Archive
Sunday, April 4, 2010
Moving into narkisr.com
Posted by ronen at 5:26 AM 0 comments
Saturday, January 9, 2010
Cool Groovy techniques
Groovy is a versatile & very powerful language to code with, as a Java super set it enables a Java programmer to write its code with all the known Java idioms & progress into Groovy land in small steps, in this post ill present two techniques that I find to be very powerful.
The first is closure initialization, in Java land its common that when we have an object A which uses another object B with non trivial construction code (which depends on A's input) than we write all the initialization code of B inside A constructor:
class ComplexInit { // our B
// ... some state that need to be initialized by users of this class
}
class UsesComplex {// our A
private ComplexInit v
def UsesComplex(){
v = new ComplexInit()
//.. some complex initialization logic which depends on UsesComplex
}
}
Another common practice is to create a factory that will encapsulate the initialization of ComplexInit class taking A as input:
class ComplexInitFactory {
def createComplexWith(UsesComplex u){
// initialization code which depends on
}
}
Groovy offers another way which I named "closure initialization":
class UsesComplex{
private ComplexInit val = {
def result = new ComplexInit()
// more logic here
}()
def UsesComplex(){
// ComplexInit is initialized above
}
}
Note that we are embedding a closure within the UsesComplex class & call it immediately after it has been defined, this resembles static initializer code blocks in Java except that it not static at all, the anonymous closure has access to its surrounding scope & can access other data members during its run:
class UsesComplex{
def today = new Date()
private ComplexInit val = {
def result = new ComplexInit()
result.a = today
result
}()
}
By separating our constructors into initialization blocks we modularize the construction of our object, making our code more readable & DRY (no separation between deceleration & initialization).
Another interesting technique is dynamic method dispatch, in Groovy we can dispatch methods like so:
class Target{
def methodA(){ println 'hey'}
}
new Target().methodA()
new Target()."methodA"()// this works too!
This means that we can dispatch methods according to run time logic:
class Target{
def calcA(){'a'}
def calcB(){'b'}
def calcC(){'c'}
def notCalc(){'d'}
}
def t = new Target()
def calcs = t.metaClass.methods.findAll{it.name.startsWith('calc')}.collect{it.name}
calcs.each{println t."$it"()}// will print a b c
Its true that Java reflection has similar capabilities however the Java API is very verbose & not as elegant, use this technique with care since it may result with hard to read code!
Thats about it for this post, let me know if you find these techniques useful in your code.
Posted by ronen at 8:13 AM 0 comments
Saturday, October 31, 2009
Synching your enviroment around
Ubuntu 9.10 has just came out & iv rushed to upgrade, upgrading my 9.04 to 9.10 via the upgrade manager is a working option but usually id rather do a clean install & get a fresh system to poke around.
The main issue that clean install brings is restoring your old environment which includes installed programs, settings files (.bashrc, .vimrc etc..), non packaged applications (usually the latest & greatest versions of Clojure, Groovy etc..).
Another issue is the need to restore these settings on multiple machines while keeping it all consistent between them, there must a better way than working it all manually!
Well the solution that iv come with involve two tools, Dropbox & AutomateIt, Dropbox is no more than a fancy folder to the cloud synchronizer which enables me to access all my settings file from any machine, lsym-ing my .bashrc, .vimrc & any other file that id like to share across machines into the Dropbox folder is all that is required.
The second part involves AutomateIt, which is a configuration management framework written in Ruby, an easy way of re-creating symlinks from my Dropbox folder onto a new system is using the following AutomateIt script:
HOME = ENV['HOME']
DROP = "#{HOME}/Private/Dropbox"
def link(src,dst)
ln_s("#{DROP}/#{src}","#{HOME}/#{dst}")
end
# Vim
link "vim/.vimrc",".vimrc"
link "vim/.vim",".vim"
link "vim/.vimclojure-2.1.2",".vimclojure"
# Bash
link "BashEnv/.bashrc",".bashrc"
link "BashEnv/.inputrc",".inputrc"
# Languages
link "prog-langs/.clojure",".clojure"
link "prog-langs/.groovy",".groovy"
link "prog-langs/.jruby",".jruby"
The nice thing about it is that it hides all the nitty gritty details that id have to figure out when using plain Ruby (or any other environment for that matter), AutomateIt wraps common tasks with a bash like DSL, unlike bash this DSL is portable across multiple unix systems & it hides many of the complexities that follow.
AutomateIt performs actions only when they are required, this solves annoying cases that rise when scripts run more than once on a system (e.g. appending text to files).
Another cool feature is package management, AutomateIt is capable of interacting with multiple packaging systems (yum, apt, gem etc..) in a transparent way, its easy to replicate installed packages onto multiple systems:
# bash
%w(terminator rlwrap).each{ |p| package_manager.install p}
# programming
%w(vim git-core).each{ |p| package_manager.install p}
# communication
%w(deluge openssh-server).each{ |p| package_manager.install p}
# misc
%w(gpodder gnome-do).each{ |p| package_manager.install p}
# installing dropbox
download_manager.download 'http://www.getdropbox.com/download?dl=packages/nautilus-dropbox_0.6.1_i386_ubuntu_9.10.deb' , :to => '/tmp/nautilus-dropbox_0.6.1_i386_ubuntu_9.10.deb'
package_manager.install ({'nautilus-dropbox' => '/tmp/nautilus-dropbox_0.6.1_i386_ubuntu_9.10.deb'} , :with => :dpkg)
Using these tools has made configuration nirvana a bit closer to me & hopefully to you :)
Posted by ronen at 11:34 AM 1 comments
Saturday, July 25, 2009
The easiest singleton around
Iv just finished watching stuart-clojure-presentation where the issue of singletons is mentioned (global & thread local ones), a note from the audience mentions delay as a solution, REPL-ing a bit shows how this works:
user=> (defn singleton-factory []
(println "creating object")
(+ 1 2))
#'user/singleton-factory
user=> (def singleton (delay (singleton-factory)))
#'user/singleton
user=> (defn usage []
(force singleton))
#'user/usage
user=> (usage)
creating object
3
user=> (usage)
3
Stuart does mention contrib singleton which has also per-thread-singleton.
user=> (use 'clojure.contrib.singleton)
nil
user=> (def t-singleton (per-thread-singleton singleton-factory))
#'user/t-singleton
user=> (defn use-twice [] (+ 1 (t-singleton)) (+ 1 (t-singleton)))
#'user/use-twice
user=> (defn use-twice-no-singleton [] (+ 1 (singleton-factory)) (+ 1 (singleton-factory)))
#'user/use-twice-no-singleton
user=> (. (Thread. use-twice) start) ; each Clojure Fn implements Runnable
nil
user=> creating object ; REPL prints on the wrong line
user=> (. (Thread. use-twice-no-singleton) start)
user=> creating object ; same thing
creating object
user=>
This should come useful when working with all those Java mutable objects.
Posted by ronen at 6:50 AM 0 comments
Thursday, July 23, 2009
Dont overflow yourself!
Clojure has many nice less highlighted features, one of these is overflow protection, this can be a true life saver:
user=> (unchecked-add 1 2); not safe but might be faster
3
user=> (unchecked-add (. Integer MAX_VALUE) 2); oops
-2147483647
user=> (+ (. Integer MAX_VALUE) 2) ; using safe arithmetic again
2147483649
user=> (+ (. Integer MAX_VALUE) 23)
2147483670
user=> (class (+ (. Integer MAX_VALUE) 23)); Clojure does the right thing for us
java.lang.Long
It does pack more than just concurrency up its sleeve.
Posted by ronen at 3:57 PM 0 comments
Labels: clojure overflow
Monday, June 29, 2009
Genericsfaction, getting some generics satisfaction
Java generics have a lot of short shortcoming, most of which are the result of the religious backward compatibility that Java is known for.
One of the most annoying "features" of generics is type erasure in which the compiler removes (almost) any trace of generic types meta data.
Iv been pondering about this issue & had a simple idea, what if we could add back in the meta data that the erasing process removed?
So, iv decided to create a proof of concept in order to show how this might work and named it genericsfaction.
Using genericsfaction requires an additional code manipulation stage in which the source code is scanned & gets its AST manipulated (meta data is introduced), each manipulated source file is dumped into a separate folder (named gen), all that is left is to compile the files under gen (instead of the original src).
At the moment there are only two enrichments implemented, the first is method input parameters annotation enrichment:
public void twoTypeParamsMet(@GenMeta(stringRep = "((Object ()) (Object ()))", classes = { Object.class, Object.class }) Map <Object, Object> map) {
// method code
}
The second is variable initialization enrichment:
public static void main(String [] args) {
List<Integer> list = (List <Integer>)MetaProxy.newInstance(new ArrayList<Integer>(),"(Integer ())",new Class []{Integer.class});
}
The reason that annotations aren't used in this case is due to this limitation.
There is no release to play with yet, however the source is up on github (mostly Clojure), I am planing on making a release as soon as ill finish to implement a validation module that uses this meta data in runtime.
Posted by ronen at 2:26 PM 0 comments
Saturday, May 23, 2009
Newify your Object
Update a generous Anonymous has left a comment that the following special macro form does the same as the newify function that i present later on:
(def nested-object (-> GrandFather. Father. GrandSon.))
Feel free to skip this entry (unless your interested in an alternative implementation).
Instantiating large nested object graphs can be tedious in any language Clojure included:
(def nested-object
(new Grandson
(new Father
(new Grandfather))))
All those new methods call get old pretty quickly and are not DRY, to remedy this will take advantage on a cool property of Clojure Homoiconicity.
Homoiconicity basically means that the code is represented by a basic data structure of the language itself (lists in the case of Clojure), this means that manipulating the AST is easy as pie!
It would be nice if we could write something like the following:
(def nested-object
(def nested-object (newify '(Grandson (Father (Grandfather)))))
The newify function takes a nested list of objects & adds new before each object, post that the function evaluates the resulting list:
(defn newify [e] (eval (newify-imp e)))
; required since used before defined
(defn- newify-rest [e] )
(defn- newify-imp [e]
(let [add-new (partial cons 'new) add-rest (partial cons (first e))]
(if (not (empty? e))
(-> (newify-rest e) add-rest add-new) e)))
(defn- newify-rest [e]
(map #(if (list? %) (newify-impl %) %) (rest e)))
The newify-imp & newify-rest functions are mutually recursive, newify-imp adds the new symbol & the first list element to the result of the newify-rest function result, the newify-rest maps each list in the rest of the list to its newified value.
This implementation could be transformed into a recursive macro that will spare us from the list escaping:
(def nested-object (newify '(Grandson (Father (Grandfather)))))
; no escaping here
(def nested-object (newify (Grandson (Father (Grandfather)))))
Ill have to dig that option later on.
Posted by ronen at 1:21 PM 2 comments