50Ply Blog

What I'm up to

Asynchronous Sequential Code Shape

| Comments

I’ve been writing more asynchronous code lately and I’m annoyed by the shape that asynchronous sequential code takes. For example:

1
2
3
4
5
6
7
8
9
fetch("/foo.json", function(text) {
   var url = text + ".html";
   fetch(url, function(result) {
      view.show(result);
      timeout(1000, function() {
          view.makeEditable();
      });
   });
});

Sure, it’s not that bad–but there’s a lot of noise in that code that’s more about it being asynchronous than it is about the actual task I’m trying to accomplish. If I was instead writing code that would run in a thread that could block freely I’d write something like:

1
2
3
4
5
6
var text = fetch("/foo.json");
var url = text + ".html";
var result = fetch(url);
view.show(result);
sleep(1000);
view.makeEditable();

But, now I’m doing potentially terrible things like updating my view from an arbitrary thread. Also, there better be a mutex hidden somewhere to protect any global state (like view.) However, regardless of the newfound dangers, the intent of this code is much clearer.

So, my threaded example is clearer but my async example is safer. Wouldn’t it be nice to have the best of both worlds? We can!

I’ve been writing more code in Clojurescript recently. Since Clojurescript has turbo-powered-lisp-like macros, we can just extend the language to support a better “shape” for asynchronous sequential code. Macros are great at transforming the shape of your code.

First, here’s what the very first example would look like translated into Clojurescript but without our shape enhancing macro:

1
2
3
4
5
6
7
8
9
(fetch "/foo.json"
  (fn [text]
    (let [url (str text ".html")]
      (fetch url
        (fn [result]
          (.show view result)
          (timeout 1000
            (fn []
              (.makeEditable view))))))))

Now, with our shape-shifting macro:

1
2
3
4
5
6
7
(doasync
  [text [fetch "/foo/json"]
   url (str text ".html")
   result [fetch url]
   _ (.show view result)
   _ [timeout 1000]
   _ (.makeEditable view)])

Looks a lot like our threaded case, right? It turns out that the code that the doasync macro generates has exactly the same effect as our other asynchronous examples. But, thanks to doasync, we get to express that asynchronous code in the more clear shape that, until now, only our threaded example had been able to achieve.

doasync is part of my MOVE example on GitHub.

Lexicographical Events

| Comments

I made up that name but here’s the big idea:

Define an event to be an ordered list where the each entry in the list provides more specific information about the nature of the event. For example:

1
[ :click,  :button,  widget-ref ]

When the event is fired, build the set of sublists built by extending the empty list by one element and fire those instead. So, firing the event above would fire these events:

1
2
3
4
[]
[:click]
[:click, :button]
[:click, :button, widget-ref]

Then, if you want to know if a specific widget is clicked, you can listen for the [:click, :button, widget-ref] event. If you want to know about all clicks you can register for [:click]. If you want a view into every single event fired then register for [].

Here’s an implementation of the idea in Clojurescript.

Merry Christmas From 50PLY

| Comments

It’s almost Christmas! Guess what? Until December 21st you can get GoTime for free!

Why? It’s in celebration of the fun, friends, family, wonderful times, and wonderful memories that make this season so meaningful. It’s because this time of year shouldn’t just be about selling things. It’s because I like you. It’s just ‘cause.

Merry Christmas!

GoTime 1.5

| Comments

The App Store has just released my latest update to GoTime. Here’s what’s new:

  • You can configure what calendars that GoTime is monitoring for events

  • You can configure how persistent GoTime should be in getting you to go. GoTime can give you one alert or it can nag you every minute until you acknowlege that you’re off.

  • GoTime can more accurately resolve locations it finds in your events. It’s now using the excellent Google Places API to help it understand which Starbucks (for example) you’re probably most interested in.

  • A few bugs were squashed related to the deletion of events.

  • GoTime won’t activate your GPS if you don’t have any events

I’ve been really happy to see the broad interest in GoTime. LifeHacker even did a writeup!

GoTime’s use of location services has been a point of some confusion so here’s a bit of clarification:

The iPhone has several methods for giving applications location information. Most people are familiar with the GPS capability and the fact that it can be a serious power-hog. GoTime only uses the GPS when GoTime is on the screen and you have events in your calendar that GoTime is updating. The rest of the time, GoTime uses the ultra-low-power “significant location change” service to keep your travel times fresh. The significant change service uses the location information that your phone already has available through the cellular network. It’s basically free from a power perspective.

Unfortunately, iOS doesn’t tell you what kind of location services GoTime (or any other app) is using so you have no way to know that GoTime isn’t being a GPS abusing power hog other than trying it out and seeing for yourself. But, you can take it from me–I’ve put a lot of thought and testing into this project and my battery is doing just fine.

I’ve had a great time having conversations with GoTime users both here and at the 50Ply GetSatisfaction support page. Thank you to everyone who has tried out GoTime so far.

GoTime Is Now Available

| Comments

I am very excited to announce that GoTime is available right now in the App Store.

No matter where you are and where you need to go, GoTime helps you stay on schedule.

GoTime syncs with your iPhone calendar and address book and uses your iPhone GPS to determine the travel time to upcoming calendar events. GoTime alerts you before you need to leave for appointments and then shows you where to go.

Mail.app Email Snooze

| Comments

Email Snooze: The Concept

You’re in the middle of something, and an email comes in. This email is important, and it needs your attention, but not right now. How do you make sure you don’t forget this email? Here’s the answer: Give your inbox a snooze button!

Here’s how it works: An important email comes in–your boss needs an update on your project, but right now you’ve got to stay focused on your task. You press a few keys (Control-Space Command-Apostrophe) and you get back to work. Now, the email is moved to your “Snoozed” folder and an alert is added to your calendar to remind you about that email in 30 minutes.

Email Snooze: How to get it

I was inspired to do this by a similar feature that can be added to gmail. I looked but couldn’t find the equivalent for Mail.app (the OSX email client), so I wrote it myself.

You’ll need the excellent and free QuickSilver application so you can create a hot key that executes the SnoozeMail script. Install that now if you don’t already have it. You won’t need to install any of the QuickSilver plugins to make SnoozeMail work.

Next, launch the AppleScript Editor and copy-paste the following code into the editor window:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
tell application "Mail"
  set theSelectedMessages to selection
  set theMessage to item 1 of theSelectedMessages
  set theSubject to subject of theMessage
  set theMailbox to "Snoozed"
  set theAccount to "Gmail"
  
  move the theMessage to mailbox theMailbox of account theAccount
end tell

tell application "iCal"
  tell calendar "Delayed Mail"
      set theCurrentDate to current date
      set fireDate to (theCurrentDate + 30 * minutes)
      set theSubject to "Follow up on delayed mail '" & theSubject & "'"
      set theEvent to make new event at end with properties {description:"Delayed Mail", summary:theSubject, start date:fireDate}
      tell theEvent
          make new display alarm at end with properties {trigger interval:-1}
      end tell
  end tell
end tell

If Mail.app is fetching your mail from an account other than Gmail, then you will need to edit the 6th line to set theAccount to the name of your email account. You can find the name of your email account by opening Mail, then opening the Mail menu, and then selecting Preferences. Next, click the accounts button and copy the account name from the Description box into the SnoozeMail script. For example, if my Description box had the text “brian@50ply.com” in it, I would edit the 6th line of SnoozeMail to say:

1
set theAccount to "brian@50ply.com"

Next, you need to create the mail folder and the calendar that SnoozeMail will be using. Create a new mail folder called “Snoozed” and create a new calendar called “Delayed Mail”. Select one of your emails, then switch over to the AppleScript editor and click on the Run button to test your script. If anything goes wrong, AppleScript should give you a helpful error message. If the email is successfully moved to your new Snoozed folder, and you see a new event in your Delayed Mail calendar, then you’re ready to move on!

Save the script into your Documents folder, and call it SnoozeMail.

After you’ve saved the script, press Control-Space Command-Apostrophe to activate QuickSilver’s configuration screen. Then select Triggers from the toolbar at the top of the window. Click on the small plus sign in the bottom-left of the window to create a new trigger. Select Hot Key from the menu.

click triggers and then click the plus to make a new trigger

Type “SnoozeMail” and QuickSilver should auto-complete the name of the script you saved. If QuickSilver can’t find it, try closing and re-opening QuickSilver to force it to search your computer again.

Click on the ‘i’ in the bottom-right of the window and then click in the Hot Key box to create the hot key that will activate this script. I use Command-Apostrophe. Next, select the scope button and pick “Enabled in selected applications” from the drop-down menu. Type “Mail” in the box and press enter.

Congrats! Now you should be able to snooze an email directly in Mail by selecting it and pressing Control-Space Command-Apostrophe! I hope you enjoy this as much as I have.

It’s Almost GoTime!

| Comments

October 28th is Go Time!

50Ply will be releasing GoTime at the end of October! GoTime integrates with your iPhone calendar and estimating how long it will take to drive to your appointments. GoTime keeps its estimates current as you go through your day, and it alerts you when it is time for you to leave.

Just For Fun

You can now play Memory Match, our free Android Game, in your browser! How quickly can you find all the pairs?