Posts about programming

Memoize for Javascript

I wrote a memoize function for Javascript today to cache file timestamps. I thought I would share it with the world. Here is the code:
function memoize(f){
    var cache = {}
    return function(){
        var keys = []
        for (var i = 0; i < arguments.length; i++){
            keys.push(typeof(arguments[i]) + ':' + String(arguments[i]))
        }
        var key = keys.join('/')
        if (key in cache){
            return cache[key]   
        }else{
            var val = f.apply(null, arguments)
            cache[key] = val
            return val
        }
    }
}
Let's say you have a function:
function f(x, y){
  return x + y * 2
}
If you memoize it:
f = memoize(f)
The first time you call f with arguments (3, 4):
f(3, 4) => 11
It will compute it, but the second time:
f(3, 4) => 11
It will merely return the cached value computed from the last time.

Note about the implementation: the equality metric used by this memoize function is: 2 objects are equal iff they are of the same type:
typeof(one) == typeof(other)
and, they have the same string represention:
String(one) == String(other)
That is it. Enjoy!
Posted by Toby 6 months ago about javascript and programming (0 comments)

Flex Compiler Slower on 64bit Mode Java on Snow Leopard

Ever since I upgraded to Snow Leopard, the my flex apps seemed to compile slower. Today, I finally had enough and took a look into this problem. First, there was the weirdness with Java on Mac in that even though the compiler is a command line application(non-GUI), it creates a application menu. I cracked open the mxmlc script, and added:
-Djava.awt.headless=true
to VMARGS. This solved that issue, but didn't make it compile much faster.
Then, after a bit of fiddling around, it turned out that putting java into 32bit mode:
-d32
fixed the problem! The difference was significant. I tested this in 2 different apps. For App 1, it took 45 seconds to compile on 64bit mode, only 9 seconds on 32bit mode. For App 2, it took 30 seconds on 64bit mode, only 7 seconds on 32bit mode. So, mxmlc performs 4-5 times slower on 64bit java than 32bit, java. Why would this be the case, I have no idea. If anyone has an idea, I'd love to be enlightened. If you come across this problem, the fix is to open up mxmlc, and edit the line that says:
VMARGS="-Xmx1024m -Dsun.io.useCanonCaches=false"
and change it to:
VMARGS="-Xmx1024m -Dsun.io.useCanonCaches=false -Djava.awt.headless=true -d32"
I hope that helps someone.
Posted by Toby 9 months ago about flex and programming (1 comments)

Taking an Average in CouchDB

More fun with CouchDB, this time taking an average of something:
// map
function(doc){
    emit(null, doc.info.size) // in place of doc.info.size, you'd put whatever
                               // value you want averaged here
}
// reduce
function(keys, values, rereduce) {
    if (!rereduce){
        var length = values.length
        return [sum(values) / length, length]
    }else{
        var length = sum(values.map(function(v){return v[1]}))
        var avg = sum(values.map(function(v){
            return v[0] * (v[1] / length)
            }))
        return [avg, length]
    }
}
The end result will be 2 values, the first is the average, the second is the total number of values that we took an average of. Phew! Who woulda thought taking an average would be so involved!
Posted by Toby 11 months ago about couchdb, javascript and programming (0 comments)

Retrieve The Top N Tags in CouchDB

I am reading up on how map/reduce works in CouchDB, think I am getting the hang of it now, thanks to this great tool. I tried the "Retrieve the top N tags" example on this page. It didn't work for me at all. So I wrote my own as an exercise. Here's my code:
// the map function
function(doc){
    for(var i in doc.tags)
    {
        emit(null, doc.tags[i]);
    }
}

// the reduce function
function(key, values, rereduce){
    var hash = {}
    if (!rereduce){
        for (var i in values){
            var tag = values[i]
            hash[tag] = (hash[tag] || 0) + 1
        }
    }else{
        for (var i in values){
            var topN = values[i]
            for (var i in topN){
                var pair = topN[i]
                var tag = pair[0]
                hash[tag] = (hash[tag] || 0) + pair[1]
            }
        }
    }
    var all = []
    for (var key in hash)
        all.push([key, hash[key]])
    return all.sort(function(one, other){
        return other[1] - one[1]
    }).slice(0, 3)
}
The approach I took was different one from the one from the example page, but I believe it to be the more correct one: rather than returning the results keyed by the tag in the map step, I would emit every occurrence of every tag instead. Then in the reduce step, I would calculate the aggregation values grouped by tag using a hash, transform it into an array, sort it, and choose the top 3. For the rereduce case, I would combine a set of top 3 choices and then again pick the top 3 among them.
Posted by Toby 11 months ago about couchdb, javascript and programming (0 comments)

Adding Real Properties to FABridge

Although FABridge is a nice tool, it's got its shortcomings. I am going to fix one of them now, namely that it doesn't give you real properties, but uses Java's getter setter convention instead. In 3 out 4 browsers, the __defineSetter__ and __defineGetter__ methods are already usable, so why not take advantage? It's really easy as it turned out. Change the addPropertyToType method to:
    addPropertyToType: function(ty, propName)
    {
        var c = propName.charAt(0);
        var setterName;
        var getterName;
        if(c >= "a" && c <= "z")
        {
            getterName = "get" + c.toUpperCase() + propName.substr(1);
            setterName = "set" + c.toUpperCase() + propName.substr(1);
        }
        else
        {
            getterName = "get" + propName;
            setterName = "set" + propName;
        }
        function setter(val)
        {
            this.bridge.setPropertyInAS(this.fb_instance_id, propName, val);
        }
        ty[setterName] = setter;
        function getter()
        {
            return this.bridge.deserialize(this.bridge.getPropertyFromAS(this.fb_instance_id, propName));
        }
        ty[getterName] = getter;
        if (ty.__defineGetter__)
            ty.__defineGetter__(propName, getter);
        if (ty.__defineSetter__)
            ty.__defineSetter__(propName, setter);
    },
 And..., voila! You got yourself real properties. Now instead of writing:
app.getTextBox()
You will be much happier writting:
app.textBox
On non-sucky browsers that is.
Posted by Toby 11 months ago about flex, javascript and programming (0 comments)

Typed Deserialization with JSON

JSON is nice, but if you use it extensively, you go against the OO style of object modeling, which says that behaviors should be attached to objects themselves. Even if you are not an OO bigot, the OO way is sometimes just far more convenient and structures your code better, IMHO. Given my past work with JYaml, it can't be that hard to read in some JSON and directly deserialize it into a typed object can it?

Say you have a Person type:
function Person(name){
    this.name = name
}
Person.prototype.sayHi = function(){
    return "Hi! I am " + this.name
}
You create an instance called tommy:
> tommy = new Person('Tommy')
> tommy.sayHi()
Hi! I am Tommy
With a little magic from a toJson function that I whipped up:
> tommyJson = toJson(tommy)
> tommyJson
{__proto__: Person.prototype, name: "Tommy"}
tommyJson is now a string representation of tommy. You can see that it sets the special __proto__ link to Person.prototype, which will do its magic when it's deserialized. Now let's deserialize it back:
> tommyCopy = fromJson(tommyJson)
> tommyCopy.sayHi()
Hi! I am Tommy
> tommyCopy.constructor
function Person(name){
    this.name = name;
}
> tommyCopy === tommy
false
As you can see, the deserialized object tommyCopy is not just a plain object literal, but has all of the behaviors of Person.

The code for toJson and fromJson is so small I don't even bother putting it on github, so I'll just post it here(You may need ecma5array if you want to run it on a sucky browser):
function toJson(obj){
    function keys(o){
        var ret = []
        for (var key in o){
            var val = o[key]
            if (o.hasOwnProperty(key)) // exclude attributes in the parent
                ret.push(key)
        }
        return ret
    }
    function quote(str){
        return '"' + str + '"'
    }
    if (obj === null || obj === undefined)
        return String(obj)
    else if (obj.constructor === String)
        return quote(obj)
    else if (obj.constructor === Array)
        return '[' + obj.map(toJson).join(', ') + ']'
    else if (obj.constructor === Object)
        return '{' + keys(obj).map(function(key){return key + ': ' + toJson(obj[key])}).join(', ') + '}'
    else if (obj.constructor && obj.constructor.name)
        return '{' + ['__proto__: ' + obj.constructor.name + '.prototype'].concat(
            keys(obj).map(function(key){return key + ': ' + toJson(obj[key])})).join(', ') + '}'
    else
        return String(obj)
}
function fromJson(str){
    return eval('(' + str + ')')
}

Posted by Toby 11 months ago about javascript, programming and prototype (0 comments)

Vector for ActionScript3

I just learned about Vector, it's a typed Array for Actionscript 3, like generics in Java or C#. However, in Actionscript 3, Vector is a one-off: it's the only class that uses the generics syntax, and developers cannot use generics in their own classes. Nevertheless, Vector gives a type-safe alternative to Array and promises big performance gains. Given that it can also give the type of the containing elements at runtime, I can use it now to drive JSON deserialization into objects too.
Posted by Toby 11 months ago about actionscript, flex and programming (0 comments)

Google Chrome Frame to the Rescue!

Bruce Eckel's prediction came true! Chrome is now an IE plugin! There's a lot of talk about it at the moment about security concerns and accessibility, but both of these discussions miss the point. The real story here, is what Google Chrome Frame means for developers. Web developers like me have longed for the following:
  • CSS 3 support
  • Canvas
  • SVG
  • Properties and other advanced features in Javascript
  • HTML 5
  • Not having to develop for a browser that sucks
Now, rather than resorting to campaigns like these, you can instead ask your users to install a plugin - much like with the Flash plugin - that will essentially run Chrome's engine inside IE 6, 7, or 8, and give you all of the benefits in the list above. The average end-user will hardly notice the difference because IE's interface will stay the same, the only things that are different are within the content pane of the browser. Given Flash's ubiquity with its browser plugin install model, it is certainly not unconceivable for Chrome Frame to become wide spread among IE users. Go back a few years: How did Flash gain this level of penetration in the first place? Answer: YouTube! Who owns YouTube now? Oops! Yes, Google could totally drop Flash from YouTube and go HTML 5 only. I doubt they would do that in reality, but that card is there for them, if they want to play it. The more probable Google strategy will be Wave, which, I gather from Google's positioning, will definitely not support IE natively. So, if Wave hits a home run and becomes the next big thing, Chrome Frame - and thus HTML 5 - will become a very viable RIA environment. Heck, some other company could very well come into the picture at this point and develop a killer app in HTML 5 that pushes it over the top also. When we get to that point - and here's me praying - it's bye bye to developing for the IE platform, forever!


Posted by Toby 11 months ago about programming, tech and web (1 comments)

HTTP Server in 5 Lines With Webrick

Usually when I am prototyping a web UI - either in Javascript or Flex, I would just write a static html, because that's the simplest thing that works. But, once in a while, it doesn't work because of the security restrictions that the browser imposes on local files. Maybe you want to use ajax calls(which is sometimes problematic on IE), trying to use the google maps api, or the FABridge, whatever the reason may be. Well, you can get around this problem easily using this ruby script:
require 'webrick'
server = WEBrick::HTTPServer.new :Port => 1234
server.mount "/", WEBrick::HTTPServlet::FileHandler, './'
trap('INT') { server.stop }
server.start
This runs a web server at http://localhost:1234/ which mounts the top level directory to your current directory.

Update: Oops, it's not exactly that easy after all. In order to prevent caching - which you will want to do if you are doing development - you will want to write an extra class. The modified script:
require 'webrick'
class NonCachingFileHandler < WEBrick::HTTPServlet::FileHandler
  def prevent_caching(res)
    res['ETag']          = nil
    res['Last-Modified'] = Time.now + 100**4
    res['Cache-Control'] = 'no-store, no-cache, must-revalidate, post-check=0, pre-check=0'
    res['Pragma']        = 'no-cache'
    res['Expires']       = Time.now - 100**4
  end
  
  def do_GET(req, res)
    super
    prevent_caching(res)
  end

end

server = WEBrick::HTTPServer.new :Port => 1234
server.mount "/", NonCachingFileHandler , './'
trap('INT') { server.stop }
server.start
Not 5 lines anymore, bummer! The code for NonCachingFileHandler was stolen  from unittest_js.
Posted by Toby 11 months ago about html, javascript, programming and ruby (0 comments)

I Learned Something About Scala

I am trying to learn Scala. Here's me trying. Don't forget to look for my write up at the end where I answer my own question.
Posted by Toby about 1 year ago about haskell, programming and scala (0 comments)

The New-Found-Love for Dynamic Languages

Posted by Toby about 1 year ago about haskell, programming and ruby (0 comments)

Describing "with"

The with statement of javascript got a lot of hate from Douglas Crockford in his famous Javascript lecture videos, as well as in this blog post. Now it gets hated on by the Ecmascript 5 spec too, where its use is disallowed in strict mode. The general consensus is that, you should never use with, ever.

But, it is so very tempting - once in a while - to make use of this forbidden feature. So I decided to write a spec for with which will uncover exactly what all the pitfalls of using it are. Then, you will decide for yourself whether you want to use it or not. Without further ado(comments are inlined with the code):
describe('with')
  .beforeEach(function(){
    this.name = 'Houston'
    this.age = 18
    this.eyes = null
    this.lips = undefined
    window.name = "window's name"
  })
  .should('get attr', function(){
    with(this){
      expect(name).toBe('Houston')
      expect(age).toBe(18)
      expect(eyes).toBe(null)
      expect(lips).toBe(undefined)
    }
  })
  .should('raise if doesn\'t exist', function(){
    with(this){
      expect(function(){namee}).toRaise()
      this.namee // but write "this." and doesn't raise
    }
  })
  .should('reference variable from outside with scope', function(){
    var hair = 'dark'
    with(this){
      expect(hair).toBe('dark')
    }
  })
  .should('do assignment', function(){
    with(this){
      name = 'Kenny'
    }
    expect(this.name).toBe('Kenny')
  })
  .should('not do assignment if attr does exist yet', function(){
    /*
    when you make an assignment to an attribute of the object in 
    question(the one you are working *with*), that attribute must 
    already exist(been assigned some value), otherwise, it will 
    behave like it would outside the with scope and assign the 
    attribute to the window object.
    */
    with(this){
      hair = 'dark'
    }
    expect(this.hair).toBe(undefined)
    expect(hair).toBe('dark')
    expect(window.hair).toBe('dark')
  })
  .should('do assignment if attr is defined to be undefined', function(){
    /*
    I had always thought that assigning undefined to an attribute 
    is the same as it having never been assigned a value at all. 
    I was wrong. But deleting the attribute will revert it to the 
    state of non-existence, as the next test shows.
    */
    with(this){
      lips = 'pink'
    }
    expect(this.lips).toBe('pink')
  })
  .should('not do assignment if attr has been ' +
    'deleted(deleting makes it "not exist")', function(){
    /*
    Deleting the attribute will revert it to the 
    state of non-existence, which makes unassignable from within
    the 'with' scope again
    */
    delete this.name
    with(this){
      name = 'tony' // this sets window.name to 'tony'
    }
    expect(this.name).toBe(undefined)
    expect(window.name).toBe('tony')
  })
  .should('delete', function(){
    with(this){
      delete name
    }
    expect(this.name).toBe(undefined)
  })
  .should('deleting makes the attribute go away, and you are' +
    'again accessing window\'s attrs', function(){
    with(this){
      expect(name).toBe('Houston')
      delete name
      expect(name).toBe("window's name")
    }
  })
  .should('be silent if deleting non-existing attr', function(){
    with(this){
      delete hands
    }
    expect(this.hands).toBe(undefined)
  })
  .should('do assignment if attr is null', function(){
    with(this){
      eyes = 'brown'
    }
    expect(this.eyes).toBe('brown')
  })
  .should('do assignment using this if attr does not exist', function(){
    with(this){
      this.hair = 'dark'
    }
    expect(this.hair).toBe('dark')
  })
  .should('var outside with scope does not override', function(){
    /*
    variables defined outside the with scope has lower precedence 
    than attributes of the object in question.
    */
    var name = 'Jen'
    with(this){
      expect(name).toBe('Houston')
    }
  })
  .should('var outside with scope does not override (2)', function(){
    this.window = 'Not window'
    with(this){
      expect(window).toBe('Not window')
    }
  })
  .should('var inside scope overrides', function(){
    with(this){
      var name = 'Jen'
      expect(name).toBe('Jen')
    }
  })
  .should('have no lexical scoping', function(){
    var instrument = 'sax'
    with(this){
      var instrument = 'trumpet'
      expect(instrument).toBe('trumpet')
    }
    expect(instrument).toBe('trumpet')
  })
  .should('erase vars after the with scope closes', function(){
    var name = 'blah'
    with(this){
      expect(name).toBe('Houston')
    }
    expect(name).toBe('blah')
  })
Full source is at github.
Posted by Toby about 1 year ago about javascript and programming (0 comments)