Tuesday, July 29, 2008

Pattern Matching

Ok quick post on pattern matching.

Here's my first use of pattern matching EVAR!


def myMethod(os : String) = {
os match {
case "Linux" => "AWESOME!"
case "Windows" => "Eh.."
case "Mac" => "Sheep!"
}
}

Notes on syntax:

  • the keyword match is followed by a matching "block" {}
  • the case keywords are followed by some selector, in this case a literal
  • the => comes after a selector and before a block to execute for that selector. Not sure of all the rules for the execution block for selectors, but so far whatever I type has worked as I expected.


Notice how it's testing for equality against a string? I can also use it to match against classes


def myMethod(someObject : AnyRef) = {
someObject match {
case obj : SomeAwesomeType => obj.doAwesome()
case obj : SomeLameType => obj.doLame()
case _ => doDefaultUnmatchedErrorRoutine()
}
}


Once again, notice how pattern matching can pull objects out by type. Think about it like an if/else block only you don't have to write the tests yourself (for the most part). Just a side note, the _ selector matches ANYTHING. So it's a great catch-all error-handler guy.

Since I'm doing this quick, we'll through in a little nugget about selectors (or whatever they're called. Selectors are pretty amazing. Scala recognizes the "unapply" method as a matcher/selector. This is used in pattern matching. I'm going to create an object that will take in a various class and return a transformed class. I can pattern match on an anyreference, and this object will still work. The unapply method should return null if it can't match, OR the None of an Option[T]. I prefer the Option[T] myself.





object SomeSillyValue {
def unapply(someModel : MyModel) = Some(someModel.getSillyValue)
}

def myMethod(someObject : AnyRef) = {
someObject match {
case SomeSillyValue(sillyValue) => sillyValue.doStuffWithSilly()
case _ => error("WTF Mate!")
}
}


Notice the syntax here. The unapply method take an argument of the object being pattern matched. The "case" statement in the pattern match identifies "SomeSillyValue" selector and in the parenthesis are named identifiers for the return types of the selector! That means in the case block, sillyValue is of the type T where Option[T] is returned by SomeSillyValue's unapply method. Yes... crazy! However it's VERY powerful and can shorten syntax while keeping readability.

Scala Marketing challenge

Here's the wrap up of comments, in my own words and in "priority" (as determined be number of times it was stated, and my own, undocumented, criteria):

  • Scala needs good free documentation for begginners to FP
  • Scala needs a good library/framework that starts to get used by big name companies
  • Scala needs a leader who can pour money into it, and corrupt it (thanks Joe!)
  • Scala needs a new name that doesn't make you think of the leading lady in Chrono Cross (although... this could be a bonus to Square-Enix fans)


Thanks to all who contributed. I'm sure some of you enjoyed the huge tirade on the Scala mailing list. To all those interesting, I plan to buy the scala book in the future and loan it to co-workers. I'd rather have a physical book as these tend to actually get read (by myself), vs. PDFs.

Wednesday, July 16, 2008

Scala Marketing Challenge

I'd like to hear from the community (or those who read this) on what they think Scala needs to do as a language to become "mainstream". This should be a prioritized list of actions the Scala team can take to ensure that Scala not only enters the spotlight but begins to pull developers from the Java community.

To make an entry, simple supply a link to your website/blog/whatever that has your list as a comment. I'll read through each one at the end of 2 weeks and pick a winner.

Monday, July 14, 2008

Method of documenting API for Actor-Based Design

So.. the more I've been toying with Scala actors in my spare time, the better feel I have for how they are used in an application and how to go about designing said applications. The key here is to rethink your application layout.

Actors allow us to bring service-oriented-architecture to a much lower layer in the application. I an now design "micro-servers" that do very small amounts of behavior, and provide a mechanism to wire in to other micro-servers. On top of this, you also need a method of documenting your service so others know how/what messages they can pass to you.

Here's an example of creating a "microserver". This contrived example is a server that will make sure all input meets a certain filter before passing it on.

First off, let's define what a "filter" means:

trait Filter[A] {
/** Determines if the given input "passes" a filter */
def pass(input : A) : Boolean
}


it's a very simple implementation, but works for us. Notice that Filter has a type parameter. Our final actor will also have a type parameter.

Now... Let's define the messages we want to send back and forth. We need a method of adding filters to a "FilterActor", a method of removing filters, a method of querying the filter list and finally a method of performing filtering action. I'm also going to add a method of telling the "FilterActor" whom to send messages onto if they successful pass the filters.

Here's our API for FilterActor

/** Adds a filter to the filter Actor's list */
case class AddFilter[A](filter : Filter[A])
/** Removes a filter from the filter Actor's list*/
case class RemoveFitler[A](filter : Filter[A])
/** Retreives the list of filters fro a FilterActor (BLOCKING-RETURN) */
case class GetFilters[A]
/** Performs Filtering on a given input */
case class PerformFilter[A](data : A)
/** Sets some listener who will be called if a given input data passes all filters */
case class SetListener(listener : => A)


Ok, so we now have a (documented) API for calling our filter manager. Writing the code should be easy! One thing I like to do (to help other developers find things) is encapsulate my FilterActor/FilterManager in an object. We'll also define the actor in the FilterManager object.



/** Contains the FilterManager/FilterActor API */
object FilterManager {
/** Adds a filter to the filter Actor's list */
case class AddFilter[A](filter : Filter[A])
/** Removes a filter from the filter Actor's list*/
case class RemoveFitler[A](filter : Filter[A])
/** Retreives the list of filters fro a FilterActor (BLOCKING-RETURN) */
case class GetFilters[A]
/** Performs Filtering on a given input */
case class PerformFilter[A](data : A)
/** Sets some listener who will be called if a given input data passes all filters */
case class SetListener(listener : A => Unit)


import scala.actors.Actor._
/** Creates a Scala actor that uses the API defined above. */
def makeActor[A] = actor {
var listener : A => Unit = {tmp =>()}
var filters : List[Filter[A]] = Nil

loop {
react {
case PerformFilter[A](data) =>
//pass if no filters
if(filters.isEmpty) {
listener(data)
} else {
if( filters.forall(f => f.pass(data))) {
listener(msg);
}
}
case SetListener[A](l) => listener = l
case AddFilter[A](f) => filters = f :: filters;
case RemoveFilter[A](f) => filters = filters filter { _ != item }
case GetFilters[A] => reply(filters)
}
}
}
}



As you can see, we now have a very self-contained, documented "micro-service". You can see, due to the "SetListener[A]" message, that the FilterActor does not need to know who it has for a final destination, this can be wired at runtime.

Here's an example usage where we will print all lines in a file that match a given regular expression. I've removed the regex filter / file reading code as an excercise for the reader (and due to my laziness).


object MySimpleGrepApp extends Application {
import FilterManager._
val fileReader = ...
val regexFilter = ...
val grepFilterer = FilterManager.makeActor[String]

grepFilterer ! AddFilter(regexFilter)
grepFilterer ! SetListener({ line : String => Console.println(line) })

fileReader.getLines.foreach {
line => grepFilterer ! PerformFilter(line)
}
}


As you can see, it's really simple for us to have nicely threaded results. With a few minor changes, we could even read multiple files at the same time and pipe all the results through the filter.

One thing I'd like to attempt in the future is defining Scala actors in such a way that you can generically wire up inputs and outputs. In this way you could define some abstract way of scripting "micro-services" together. Even more interesting would be a way to architect an actor-based system using some kind of Inversion of Control container like Guice or Spring. If you could reliable define message passing interfaces and enforce them somehow, you could have a very powerful, scalable architecture tool.

I'm thinking that I may have jumped a lot of my audience in terms of Scala understanding for using the actor-api. Once again I think I may do a post detailing pattern match (as I understand it).

Saturday, July 12, 2008

Eclipse-Maven Integration Rumble

I have no idea what the Eclipse foundation was thinking when they decided to provision TWO maven projects ( Q -> IAM and m2eclipse -> M2E ... Eventually one project has to win and one has to go away. I'm not sure how they're planning on making the final decision, but I know I wouldn't want to be the one to make that decision.

I recently read some email sent publicly across IAM's newslist that causes some concern (See here). I'll recap the summary:

Abel, the project lead of Q, wanted to attempt some collaboration with m2e, because it doesn't make sense for two eclipse foundation projects to be doing the same thing. From what I gather of the public parts of this conversation the following went down:


  • Abel: We should Collaborate on parts of our software
  • Eugene/Jason (m2e Leads): Sounds like a good idea
  • Abel: You should look at our "xyz" feature it's well done
  • Eugene/Jason: You should look at *our* "xyz" feature it's well done
  • Name calling, Bad Blood and FUD (back and forth on both sides)...
  • HIGHLIGHT: Eugene/Jason: We never took your patches because they were badly written (I find this most amusing after looking at Abel's code...)


Ugh.. It looks ugly. Here's what I know...

History of My Maven usage:

  • Fall 2006 - Took graduate class that introduces Maven as the build system. Learned why it was worth learning
  • Wanted to find an integration plugin for eclipse. Tried m2eclipse. Worked for class, but was slightly flaky
  • Fall 2007 - Started using Maven at work. Tried m2e. WAY too many issues. Switched to Q (somehow it had entered my radar). Q wasn't perfect, but it didn't affect my daily development like m2e did.
  • Winter/Spring 2008 - Request some features in Q and attempt to integrate with the Scala maven plugin. Abel provides me with a TON of information and *personally* keeps me up to date on new features.


Anyway, I only have good things to say about Abel so far. I'm unaware of how things went down during the Q | m2e schism, but it looks like there's still bad blood. I've seen good things from the m2e team, and many good things from Q. I'd like to see them work together.

My impression of these emails has been that the m2e guys still are upset about Q splitting off. From what I see of their new features, it appears to have been the best thing for that project. However, after looking at the source code for both of them, I'd choose Q as the baseline. Yes, that's the side I would take, I'm sure it's not a shock to most people. Here's the deal though... If the Eclipse foundation would just choose one project, I'd support that one. I would hope it's Q, but it doesn't matter to me, as long as whatever project "wins" is (or becomes) high quality.

Make your own decisions. Try both plugins. Choose the best. Eventually they'll either need to combine to survive, or the better will end up with more collaborators and have to give up. I've already made my decision, but don't let that influence you. Do what's best for your needs.

Also, I'd rather not see my comment area become a battle ground for the two plugins... so please keep things civil on this blog.

Saturday, July 5, 2008

Option class for better null

Now that I've been using Scala for a while, I'm starting to learn a few niceties that Scala provides. One of these is the Option class.

The Option class is designed to replace/remove null pointer exceptions. So... first of we'll show you how it works. To create an option variable, you declare it as "Option[T]" where T is the type you'd like to get out.


class MyClass {
var possiblyEmptyString : Option[String] = None;
}


In the above example, I'm creating a class with a "possibly empty string". I'm assigning it a value of "None". Think of None as a version of null, but nicer.

When you're ready to assign a value to an "Option" you do so like this:

def assign = {
possiblyEmptyString = Some("String");
}


How do we make use of an "Option"? One of the following ways:

def doStuff = {
// 1) Check to see if it's defined
if(possiblyEmptyString.isDefined) {
doStuffWith(possiblyEmptyString.get))
}

// 2) Use a default
doStuffWith(possiblyEmptyString.getOrElse("MyDefault"))

// 3) Patern matching
possiblyEmptyString match {
case Some(string) => doStuffWith(string);
case None => logError("STRING UNDEFINED!");
}
// 3) Foreach
possiblyEmptyString foreach { string => doStuffWith(string) }
}



So.. first of, you can check an option to see if it's "empty" (None) or "defined" (Some). I'm also using the "get" method here. Get will return the value of the option, or do something crazy if the option isn't defined. (Not sure what as I haven't done that yet).

Next up is the getOrElse. getOrElse will return the value in the option (if not None), or return the value (or return value of the closure) passed in as an argument. This is my favorite to use for connections. I have some connections that will set themselves to None on errors. Everytime I do something with the connection I call getOrElse(reconnect). Reconnect will reconnect to the socket/database/etc. AND reset the Option[Socket/Connection/etc] to point to the new connection AND return the new connection. This means that if the option is None, i will automatically reconnect, but if the connection is ok, we return it. This allows the code to go along blissfully unaware of connection issues.

The next option is my favorite for using an Option value. You do pattern matching on the value and extract it correctly (or None). I think I may cover pattern matching in more detail in my next post, as I'm running out of time here.

Lastly is the foreach loop. It's guaranteed to only return the value in a Some object, so the closure won't get called for a None object. I'm not quite a big fan of the syntax, but it works.