chrislewis's posterous

I am a software developer, perpetual student, and prudent observer. I am fascinated by technology, aesthetics, language, and by humanity.

bitlyj 2.0 Available

Bitlyj 2.0 is out and available through maven central or direct download. For a more detailed overview, see the QuickStart page, but here's a teaser. Assuming the imports:

import com.rosaloves.bitlyj.*;
import static com.rosaloves.bitlyj.Bitly.*;

and credentials:

String user = "user";
String apiKey = "R_XXXXX";

you shorten a URL like this:

as(user, apiKey).call(shorten("http://rosaloves.com/"));

Noteworthy features, as they appear on the project page:

  • Concise DSL syntax with obvious semantics == bitly interaction with no boilerplate.
  • Natural error handling with no checked exceptions. If you want to deal with exceptions, catch BitlyException and access the delivered message (yields bitly's status text).
  • J.mp support baked in, with the same DSL sugar.
  • Runs on Android.
  • Zero dependencies.
  • Flexible API. Bitly methods are no longer hard-wired to an interface, so evolution is possible without API breakage.
  • Extensible API. Implementing your own methods is simple: implement the functionality in an implementation of BitlyMethod?. You get core error handling for free, and you can even implement specialized methods not supported by bitly.
  • Access to other bitly-powered services is simple: implement Provider (two methods).

The library is well-tested, but you run into a problem open an issue (or post to the list).

Enable Conditional Comments in Lift (Production run mode)

IE's conditional comments are simultaneously the warts of a fragmented web and a refuge for weary web developers. If you want to deliver a hack-free, consistent(ish) and cross-platform experience to your user's you most likely find yourself using them. When running in the Production run mode, Lift removes all (x)html comments (in all modes except Development, in fact). This poses a hurdle if you are in the aforementioned category of developers (and you should be).

Like most things in lift, this behavior is easily modifiable, but finding out where and how may not be so obvious. Here's how to enable comments in the Production run mode via Boot: 

package bootstrap.liftweb

class Boot {

  def boot {
    // I want conditional comments.
    LiftRules.stripComments.default.set(() => false)
  }

}

Much of Lift's behavior is dictated via LiftRules, so when in doubt, check there.

Binding Lift's run mode to GAE's Environment

Lift supports run modes, a feature which makes it easy to tweak the application depending on its environment. This is useful for enabling/disabling features, changing things like a system's sending email account, rendering a google analytics javascript block, et cetera. In Lift this mode is dictated by the run.mode system property which, in some environments, can be a bit painful to change.

For App Engine, however, there is a simple solution: bind Lift's mode directly to the GAE environment:

package bootstrap.liftweb

class Boot {
  def boot {
    
    System.setProperty("run.mode",
      System.getProperty("com.google.appengine.runtime.environment"))
      // the rest of your configuration... 

  }
}

GAE supports local development through a local server, complete with working and faux services. Using appengine-web.xml you can configure system properties, but there isn't a simple way to vary these settings according to the GAE environment (perhaps a resources plugin for sbt is in order...).

However, GAE, like Lift, identifies its environment using a system property. Incidentally, the two settings it uses align with Lift's run modes: Production and Development.

bitlyj 2.0 (beta) Available

bitlyj 2.0 is ready for public testing. I'll stop flooding my blog with such announcements, and refer interested parties to the google group. Have a look at my inaugural post for an idea of the direction (which you can and should help mold).

bitlyj 2.0 in Trunk

Ok, so first off I apologize for not following through with a bitlyj 1.1.0 release. I couldn't find the time or motivation, so I let it slide. I had planned to replace bitlyj entirely with a lighter library in Scala, but then accepted that there many users who probably can't (or don't want to) have that as a dependency. Therefore, even though I'm a post-java type, I've gone ahead and started working on bitlyj 2.0. This is a simpler rewrite of 1.0, with an approach to extensibility that doesn't make many assumptions about the future of bitly (unlike 1.0). It also makes an effort to be even more expressive than 1.0, with more attention paid to a DSL-like interaction. The 2.0 api is semi-stable and available in trunk, as well as a jar on the project site. I will get snapshots up soon. Use it and give feedback!

Scala on Android Gotcha: HelloGridView Error

Short Version

If you are working on the HelloGridView example in scala, you'll quickly run into a problem. Assuming you've translated the java properly, scalac will fail to compile citing this line in the ImageAdapter:

 

imageView.setLayoutParams(new GridView.LayoutParams(85, 85));

 

Change this to:

 

imageView.setLayoutParams(new AbsListView.LayoutParams(85, 85));


That's android.widget.AbsListView.

 

Long Version

I just got the Droid Incredible, and it is freaking awesome. I was excited to start hacking on some android code over the weekend, in scala. The first thing I did was shop around for a sane toolchain. I'm a fan of sbt, so I wanted a simple way to write android code without an IDE telling me how things need to be done. This is totally possible, thanks to the design of the SDK, and if you are looking to pair sbt with your editor of choice (jedit here), I suggest you read through this excellent post on getting started. Total cake. I also must direct you to a more comprehensive presentation by Nathan Hamblen, which goes into detail about various challenges, considerations and gotchas you should be aware of when writing scala for android. Now, back to the problem of GridView.LayoutParams.

The problem is that there is no such type. Let's look at ImageView, a subclass of View by which it inherits setLayoutParams. This method wants an instance of ViewGroup.LayoutParams, a static inner class that is sometimes overridden to implement view-specific mangling. If you poke through the API, you'll find several parings of layouts and their layout-specific subclasses, like LinearLayout and LinearLayout.LayoutParams. GridView has no such companion subclass, even though the example references it in the source, which does in fact compile in java and function correctly.

How can this be? GridView is a ViewGroup, which defines the static inner class LayoutParams. In java, it is perfectly legal to reference a static member defined in a super class by way of its sub class. Scala has no statics, and instead deals with static java members as members of a singleton or companion instance. This is fine, except that it means we cannot refer to GridView.LayoutParams as we could in java, because GridView defines no such class.

My first attempt at a workaround was to simply use a raw instance of ViewGroup.LayoutParams instead:

 

imageView.setLayoutParams(new ViewGroup.LayoutParams(85, 85)); 

 

It compiles. Sweet! Success! Next I sbt reinstall-emulator (install the compiled apk into a running emulator via sbt), fire up the app, and BOOM - runtime error. Well crap. What happened? Type-unsafety happened. Use adb logcat to peep the logs, and you'll find a nice little ClassCastException coming from GridView. Ok, let's look at the GridView source. I'm running against an older version of the android API, but line 936 is the culprit:

AbsListView.LayoutParams p =
(AbsListView.LayoutParams)child.getLayoutParams();

That's an explicit cast. Yuck. Look again at the hierarchy and you'll see that AbsListView.LayoutParams is, naturally, a sub class of ViewGroup.LayoutParams, which in turn means that casting ViewGroup.LayoutParams to AbsListView.LayoutParams is impossible. However, now that you've looked under the hood you know that GridView expects its children to express their layout parameters as instances of AbsListView.LayoutParams. Sure enough, switching that in solves the runtime problem, but it introduces a new one. The android API may, for some reason, require a change to GridView such that AbsListView.LayoutParams is traded for something else (like a real GridView.LayoutParams type). Arg! That means code breakage!

What do we do about this problem which, at its core, is an issue of scala/java interop? Here are 3 options:

  1. Code to the type we know the API is using, like we did above. This works, but renders us quite vulnerable to changes that upstream vendors (like the android devs) make.
  2. Use java. In cases like this, you could argue that it makes more sense to use java, especially given that several tools handle mixed-mode projects quite well (maven included, although though I've experienced mixed-mode issues at its hands, while sbt has been solid).
  3. Abstract this pain behind something that will vend the required instances. This might mean a function that yields AbsListView.LayoutParam instances, but provides you safety in its centralization. If the android API changes, you make one change.

My preference is number 3. I'm not a masochist, so that rules out 1 (and perhaps 2). Also, if I wanted to write java for android, I'd write java, not scala. 3 makes perfect sense. Abstractions are, after all, a balm to a developer's wounds.

bitlyj 1.0 and bit.ly v3

Last Tuesday, bit.ly announced version 3 of the API to their URL shortening service. Version 3 is structurally similar to 2, however the endpoints are now versioned as part of the path instead of a query parameter. In addition, the available methods have been changed.

The 1.0 release of bitlyj will completely break when the 2.0.1 endpoint is removed. Jehiah Czebotar, the gatekeeper of the API, has vaguely implied that this might happen in a few months.

On the bright side, it seems many issues have been addressed, including the two I opened (2, and 3).

My plans for bitlyj are to release a quick 1.1.0 version, which will preserve the existing API as much as possible (the info call is no longer available), as well as add a call or two (expand short url). Expect a preliminary release within a week or two. After that I will focus new development on a simpler library written in scala and powered by dispatch - full compatibility with java intact.

bitlyj: 1.0

UPDATE: Stable artifacts are now available on maven central! Thanks to Sonatype for providing free artifact hosting service for open source projects. For your mavenized open source project, I recommend it.

 

I've released bitlyj as 1.0 stable. If you need to shorten URLs from java using bit.ly (or j.mp), get it here. On a related note, if anyone has gone through the hoops of publishing maven artifacts to maven central, drop me a line.

A Look at How Scala Compiles to Java

Consider this contrived example, based on an example from Beginning Scala. The point of the snippet was to demonstrate the congruency between using the higher-order functions map, flatMap, foreach, and filter (see Iterable), and performing the same operations inside a for comprehension.

object App {

  def isEven(i: Int) = i % 2 == 0

  def isOdd(i: Int) = i % 2 == 1

  def main(args: Array[String]): Unit = {
    val n = (1 to 10).toList
    n.filter(isEven).flatMap { i => 
      n.filter(isOdd).map(j => i * j)
    }
}
}

Save this code to a file named App.scala, or anything you want (scala doesn’t have the same file/class name restrictions as java). Assuming you chose App.scala, compile it:

clewis$ scalac App.scala

Now check out the generated class files (ls App*class). You should see the following:

App$$anonfun$main$1.class
App$$anonfun$main$2$$anonfun$apply$1.class
App$$anonfun$main$2$$anonfun$apply$2.class
App$$anonfun$main$2.class
App$.class
App.class

Why were 6 classes compiled from this one singleton definition? Let’s start with App.class and App$.class.

The Singleton Object

Scala does away with Java’s statics. Instead we get singleton objects, which are declared with a syntax similar to that used for class declarations, but using the object keyword instead. When a singleton object shares the same name as a class, it becomes that classes “companion” object. Companion objects have special privileges, including access to private instance fields on instances of the companion type. In this example, App is simply a singleton object, since we haven’t also defined a class named App.

The Scala compiler implements companion objects by generating an anonymous class inside the companion class (the class of the same name as the object). The same is done for singleton objects, but the compiler also generates the containing class. Like the Java compiler, Scala names anonymous the class as [class name]$. Because we created an object named App, we get 2 classes: App and App$.

Higher Order Functions and Their Function Arguments

In Scala, functions are objects; instances of one of the FunctionN traits. Of course this knowledge isn’t obvious by the Scala syntax, and that’s part of the beauty: it just feels right. The compiler compiles any functions down to anonymous classes inside the containing class. If you understand Java’s scoping rules for inner classes, then you should now have some understanding of how Scala implements closures.

Methods in Scala are also different from functions. Methods are functions defined as part of a class definition with the the def keyword. Functions are instances of one of the FunctionN traits, and the Scala syntax provides several different ways to express them tersely. Methods are the only primitives (non-objects) in Scala, but the compiler makes it easy to promote methods to function instances. Back to our example, notice that we define the methods isEven and isOdd in our singleton object. They are method primitives, not functions. Because the compiler recognizes that methods often want to be treated as functions, it makes provisions; one such provision is that we can pass a method to a higher-order function.

Method Promotions

In order for the compiler to promote a method to a function instance, it must create an anonymous class for that instance. In our example, we first pass the method isEven as an argument to the higher-order function filter, and so the compiler generated the class App$$anonfun$main$1, which is our promoted method. Note that we also pass the isOdd to a subsequent call to filter, a promotion for which the compiler generated the class App$$anonfun$main$2$$anonfun$apply$1.

Function Literals

We’ve covered all but 2 of the generated classes. As it turns out, there are still 2 functions we haven’t discussed in the series of transformations. Take another look:

n.filter(isEven).flatMap(i => n.filter(isOdd).map(j => i * j))

Did you see them? If you’re new to Scala, you may not spot them at first because they are using function-literal syntax. The functions flatMap and map also take functions as arguments, and so we define them literally, embedding the one passed to map inside the one passed to flatMap. For these two function literals, the compiler generated the anonymous classes App$$anonfun$main$2 and App$$anonfun$main$2$$anonfun$apply$2.

To seal in what’s happening here, fire up the Scala REPL and run this code:

List(1,2,3).map(j => j + 1)

Now run this code:

List(1,2,3).map(new Function1[Int, Int] {
        override def apply(j: Int) = j + 1
})

The two do the exact same thing, because they are exactly the same.

The literal syntax may look strange, and even non-obvious at first. I thought so too, but it didn’t take long for me to greatly appreciate and recognize it as easily as you might recognize a class definition.

A Word on the Class Names

You may have noticed a pattern in the anonymous function class names. For starters, they’re prefixed with App$$anonfun$main$ and then continue in with 1.class and 2.class. There’s also another level nested inside the first level. If you inspect each of these using javap -c [class], you’ll notice the ordering and nesting follows the order in which we use function objects (by passing them as arguments to other functions).

  • isEven is the first function we pass, so it is the first function for which an anonymous class is generated, yielding App$$anonfun$main$1.
  • The second is the literal function passed to flatMap, so App$$anonfun$main$2 is generated for it.
  • The third is isOdd, yielding the class App$$anonfun$main$2$$anonfun$apply$1. This function is used inside the function passed to flatMap. It’s the first function in this scope, and it’s nested, so its name reflects its nesting and order in the sequence.
  • Finally we arrive at the literal function passed to map>, resulting in App$$anonfun$main$2$$anonfun$apply$2. It’s the second function referenced inside the function passed to flatMap, and so its name also reflects its nesting and order.

This ordering and nesting is deliberate. In Java, an inner class has access to its parent’s scope, which includes class instance variables and local variables (if the inner class was created in a method). This is what makes closures in Scala possible. Look again at the literal function passed to map:

n.filter(isEven).flatMap(i => n.filter(isOdd).map(j => i * j))

The function multiplies a “free” variable i by its single argument j. Where did i come from? Again, this function is defined inside another literal function passed to flatMap. That function receives a single argument, which it labels i. Because the function passed to map is nested inside the one passed to flatMap, it has access to that scope.

Lift Off

I arrived at the FGM building by way of my couchsurfing host, Jenny. At the moment, Reston looks a bit like London (at least if you look straight up). Fall has painted the leaves brilliantly, a sight I’m left wanting in Florida.

Jenny graciously dropped me off at the FGM building on her way to school (she’s a school teacher). I gladly accepted arriving an hour early for a free ride, and so I just started wandering the office park. I stumbled on this office “cafe” as it were, and here I sit. I seem to be just outside a free guest wifi network, but that’s ok. For a first-timer at an unconference, or any tech conference for that matter, I feel fairly prepared.

I’ve just made my way into the FGM suite. So far we’re about 32-30 strong!