A little Velocity math trick and a note on empty lists

Couple of li'l technotes today in response to reader questions.

Note #1: Generating random numbers in VTL

First topic came from user PW. He'd been searching for a way to get a handle to a random number generator by creating a dummy Java Math object or some such workaround (sometimes, these hacks are necessary to grab exotic objects from outside of Velocity proper).

I tipped him off that MathTool is already available as the object $math in Marketo's Velocity context, so there's no need for a hack.

#set( $random = $math.random(1, 20) )

So that's easy. What's more interesting is what he was using the function for. He has a list (Velocity ArrayList) of 20 possible pages on his site, like

#set( $pages = [ "myProduct1.htm", "myProduct13.htm" ... "myProduct99.htm" ] )

And now he can can link to one of the 20 pages at random: http://mysite.com/${pages[$random]}.

Of course, this doesn't work as a split test per se, since the only way you know which URL was offered to a lead is if they actually visit the page. But it's a cool way to “mix it up” at send time.

Note #2: Checking for empty lists the right way

So I kind of played myself on this one, helping out user CG with what I referred to as a job “too easy to bill for.” It's easy, but that didn't stop me from making a rookie mistake at first.

CG was working with a list $signaturesList that might be empty, and you never want to look for an index [0] in an empty array (this will cause Velocity to fail, hard). So in my first draft I simply checked for falsy array length, like

#if( $signaturesList.size() )
  #set( $mostRecent = $signaturesList[0] )
#end

Oops! Must have been writing too much JavaScript lately, since this code assumes that if .size() returns 0, the condition will be falsy enough to fail (for those that aren't familiar, falsy means “not actually Boolean false, but treated as false in a Boolean context.” But in Java (and in Velocity) .size() returns an object of type java.lang.Integer, a.k.a. a boxed numeric value. And any Integer is truthy (since it's a full-fledged Object, not a raw value)! So this did nothing to avoid fatal errors.

The correct way to do the comparison is

#if( $signaturesList.size() != 0)
  #set( $mostRecent = $signaturesList[0] )
#end

Bcause of the explicit numeric comparison, an array size of 0 will be equal to number 0.

A more OO way to do the same, but which may be unnerving to people accustomed to more dynamic languages, is

#if( !$signaturesList.compareTo(0) )
  #set( $mostRecent = $signaturesList[0] )
#end

compareTo explicitly casts the Integer to the raw numeric value and compares to the numeric 0, but then you have to negate the whole comparison, which seems clumsy.

And yet another way is to eschew size() and use the convenience method isEmpty() like

#if( !$signaturesList.size().isEmpty() )
  #set( $mostRecent = $signaturesList[0] )
#end

Which one you use is up to you, but make sure you use the same pattern in all your code.