Friday, December 20, 2013

Making a Piña Colada in Haskell: It's All About Concurrency

I was reading The Pragmatic Programmer this morning, and it got me to thinking about Haskell.

Consider the following "function" for creating a piña colada:

  • Open blender
  • Open piña colada mix
  • Put mix in blender
  • Measure 1/2 cup white rum
  • Pour in rum
  • Add 2 cups of ice
  • Close blender
  • Liquefy for 2 minutes
  • Open blender
  • Get glasses
  • Get pink umbrellas
  • Serve

It's very easy to understand and very linear.

Now consider the following diagram that conveys which parts can be done concurrently:

This description of the recipe is quite a bit more complex, but it's a lot more obvious which things can be done concurrently.

There are a lot of approaches to concurrency. For years, we've relied on our CPUs to give us some implicit concurrency. The CPU can look at the code at a very micro level and figure out which assembly instructions can be done concurrently because they're working with different parts of memory, etc.

Threads and processes also provide concurrency, but they're at a very different level, and it's very far from implicit.

Node.js also provides concurrency. However, telling Node.js which things can be done concurrently while responding to a request still takes a lot of careful thinking. You don't have to do anything to get Node.js to handle multiple requests at the same time. However, if you need to make three REST calls in order to respond to a particular request, it's up to you to notice whether or not you can do those calls concurrently, and if you do decide you can do them concurrently, it still takes some explicit coding to make it happen.

One of the essential problems is that it takes work to get from that nice linear description of how to make a piña colada to one in which all the opportunities for concurrency are explicitly stated. That's what got me thinking about Haskell again. Maybe laziness isn't such a bad idea after all ;) In Haskell, it's a lot easier to separate describing the steps necessary to do something from actually taking those steps. You can describe the steps in a way that makes sense to you, but let Haskell decide at runtime what order to take those steps in. Admittedly, I'm hand waiving a lot, and I haven't actually read Parallel and Concurrent Programming in Haskell, but I just have this feeling that Haskell makes you think in a way that the concurrent description of the recipe above will just kind of happen naturally.

Here's a fun exercise for the reader. Write a program that implements each of the steps above by doing a REST call. For instance, to "Open blender", just do a post to some server with the string "Open blender". The server doesn't really have to do anything (we'll just pretend). Implement the entire recipe using the opportunities for concurrency provided by the diagram above. Can your system figure out what things can be done concurrently automatically and then do them concurrently automatically? Bonus points if you can you make multiple piña coladas at the same time. Double bonus points if you can write code that is somewhat readable by someone unfamiliar with your system.

Footnotes:

There are a lot of things related to what I'm talking about such as Flow-based programming, the Actor model, etc. On the other hand, perhaps there are no silver bullets.

I'm not a real Haskell programmer or a Node.js programmer.

In fact, I've never even had a piña colada, so I could be way off base here ;)

Monday, December 16, 2013

Books: The Soul of a New Machine

I just finished The Soul of a New Machine by John Tracy Kidder. In short, I loved it!

Computers have changed since 1981, when Tracy Kidder memorably recorded the drama, comedy, and excitement of one companys efforts to bring a new microcomputer to market. What has not changed is the feverish pace of the high-tech industry, the go-for-broke approach to business that has caused so many computer companies to win big (or go belly up), and the cult of pursuing mind-bending technological innovations. The Soul of a New Machine is an essential chapter in the history of the machine that revolutionized the world in the twentieth century.

This is an oldie, but a goodie. It even won the Pulitzer prize. The whole drama is still very relevant today. It reminded me a lot of Hackers: Heroes of the Computer Revolution and Steve Jobs' biography. It definitely had elements of both, so if you enjoyed those, you'll definitely enjoy this one.

Saturday, November 30, 2013

Is the Modern Smartphone a Computer?

Of course it is!

If you look at the history of computers, the modern smartphone has all the same characteristics that computers have had since at least the 50s and 60s. It has a "central processing unit". It has memory. It has input/output facilities. It runs system software as well as application software. It has a mechanism for persistent storage.

If you think about the big revolutions in computing, things become very obvious. First we had mainframes. Then minicomputers. Then microcomputers. Then personal computers. Now we have smartphones. Each generation is smaller in size than the previous generation. And each generation is larger in ubiquity than the previous generation.

In the days of the mainframe, there was a talk about ubiquitous computing where one of the speakers predicted millions of computers. One of the audience members thought to himself, "That's the stupidest thing I ever heard. Why would anyone need millions of computers? It's not like they're going to put them into every doorknob." Decades later, that audience member returned to that same hotel, and he had to use a key card to get into his room--they had put a computer into every doorknob. It's only fitting we should have one in our pockets as well!

Friday, October 11, 2013

My Wireless Sucks!

The WiFi at my house has been somewhat slow and unreliable lately, so I decided to look into it. I did a lot of experiments with Speakeasy's Speed Test. I also upgraded my wireless access point from a Linksys WRT54GL to a ASUS RT-AC56U, although that wasn't strictly necessary. I fixed it to the point where my DSL connection is once again my bottleneck. Here's what I learned.

First of all, the "wireless neighborhood" I live in is very different these days than when I first setup my wireless access point. When I first set it up, I only had 1-2 devices connected to it, and there were no other wireless access points in the neighborhood. These days, I have 3 wireless devices connected to my TV, 7 Nexus 7s, 2 laptops, 2 phones, and a Rasberry Pi all connected to the same access point. Furthermore, there are 5-7 wireless access points in my neighborhood (which is still low compared to some neighborhoods). Since wireless bandwidth is a shared resource, I'm sure there's quite a lot of contention these days.

Another thing I noticed is that a lot of the APs were using channel 6. Simply switching to channel 11 made my wireless stop sucking. My guess is that newer APs are better at picking the best channel than older APs are, but I don't know that for certain.

Furthermore, I suspect that my Linksys WRT54GL was dying. Since I have a 100 year old house, devices tend to die from time to time. Hence, I've had to buy a couple Linksys APs over the years. Sometimes doing a factory reset and then reconfiguring it is enough to fix the problem. However, this time, even though I could log into the device, when I tried to do a factory reset, it didn't work. I wonder if that could possibly do with old flash memory.

Here's another trick. My buddy at work, Chris Dudte, pointed out that almost everyone has 2.4Ghz devices and APs these days, whereas very few people use 5Ghz, even though the 802.11a standard has been around forever. If you're confused by the different frequencies and the different 802.11 wireless standards (as I was), check out this useful overview. I was able to setup a 5Ghz network for my wife and I (since we have laptops and phones that support 5Ghz), whereas the kids are on a 2.4Ghz network (since their Nexus 7s don't support 5Ghz).

As I mentioned, I upgraded my wireless access point and router from a Linksys WRT54GL to an ASUS RT-AC56U. The guy at work who's in charge of wireless gave me a thumbs up when I told him that, so I assume it was the right decision. Although I was able to fix my problems with the Linksys WRT54GL simply by changing channels, I'm excited about the ASUS RT-AC56U for a few reasons. My favorite feature is that I can use one device to run a 5Ghz protected network, a 2.4Ghz protected network, and a completely open, but segregated guest network. Previously, I was only using a 2.4Ghz completely open network (because I'm a fan of open networks). It's nice to be able to continue to provide an open network, while segregating and protecting the rest of my house. There are a ton of other features as well, such as the ability to plug in USB hard drives and USB printers, but I haven't tried any of those features yet. I'm also excited to try the new 802.11ac wireless standard that it supports, but I don't have any other devices that support it yet.

Since DSL is still the bottleneck, you might wonder why faster wireless speeds matter. When all of your devices only talk to the internet and rarely talk to each other, it probably doesn't matter. However, once in a while, I need to transfer things from one laptop to another. With the Linksys WRT54GL, transferring files between laptops over wireless was ridiculously slow. With the ASUS RT-AC56U, it's much better. Of course, I prefer to keep a cross-over cable handy when I move large amounts of data between laptops, but it's nice to have the wireless network if I only need to transfer a couple gigs.

Since I've mentioned DSL multiple times, you might wonder why I don't switch to cable. One reason is that I don't want to run cable to my house. I just spent a lot of money putting new siding on my house, and I don't want the cable guy to mess it up trying to punch a whole through it. However, the biggest reason I don't want to switch to cable is that Comcast cable is well known for being one of the most disliked companies out there. It routinely has the lowest customer satisfaction ratings. Hence, I stick with DIRECTV and AT&T DSL (which was originally SBC Yahoo DSL).

By the way, one thing that surprised me was that I can actually get faster download speeds over my T-Mobile phone (while on BART) than I can over DSL. However, the T-Mobile coverage at my house sucks, as does AT&T, Sprint, and Verizon.

If you're interested in the raw data for all of my tests, here it is:

Linksys WRT54GL (several years old):
 Wired:
  Download: 5.13Mbps
  Upload: 0.59Mbps
 Wireless (originally channel 6):
  Download: 1.33Mbps
  Upload: 0.43Mbps
 Wireless (changed to channel 11):
  Download: 5.13Mbps
  Upload: 0.60Mbps
 Downloading 1.1GB from one laptop to another over wireless: 15-20mins
ASUS RT-AC56U ($200, new at Frys):
 Wireless 5Ghz (with QoS enabled, on top of my microwave):
  Download: 5.19Mbps
  Upload: 0.58Mbps
 Same on 2.4Ghz.
 Downloading 1.1GB from one laptop to another over 5Ghz wireless: 2-3mins
Using my T-Mobile Android phone as a personal HotSpot (over 3G, I think):
 Download: 8.35Mbps
 Upload: 0.53Mbps

Thursday, October 10, 2013

Books: Programming Elixir

I started reading Programming Elixir by Dave Thomas, the same guy who wrote "Programming Ruby" and who co-authored "The Pragmatic Programmer". So far, I'm really enjoying it!

Here's a quote from p. 24 that I think is particularly compelling:

This is a book about thinking differently; about accepting that some of the things that folks say about programming may not be the full story.

  • Object-Orientation is not the only way to design code.
  • Functional programming need not be complex or mathematical.
  • The foundations of programming are not assignment, if statements, and loops.
  • Concurrency does not need locks, semaphores, monitors, and the like.
  • Processes are not necessarily expensive resources.
  • Metaprogramming is not just something tacked onto a language.
  • Even if it is work, programming should be fun.

Of course, I’m not saying that Elixir is a magic potion (well, technically it is, but you know what I mean). There isn’t the ONE TRUE WAY to write code. But Elixir is different enough from the mainstream that learning it will give you more perspective and it will open your mind to new ways of thinking about programming.

So let’s start.

And remember to make it fun.

Wednesday, October 09, 2013

Pimsleur Spanish Phases 1-3

I just finished Pimsleur Spanish phases 1-3 which I bought on audible.com. In short, I thought they were fantastic!

Each phase consists of 30 units, each about 30 minutes long. Hence, I did 90 units altogether. That sounds like a lot, but I did almost all of them while driving to and from work when I worked in Mountain View. I streamed them from my phone through my stereo using bluetooth.

Before I started, I already had a decent grasp of Spanish. However, I started Pimsleur Spanish from scratch. I'm normally a very visual learner, and Spanish is a pretty easy language to learn visually since it's so phonetic. However, I needed something to do while driving upwards of three hours a day, and this fit the bill. I really like how conversational it is. It constantly pushes you to say new things in new situations using your existing knowledge of vocabulary and grammar.

I know that some people have said that they thought Pimsleur Spanish was a little boring compared to Rosetta Stone. However, Rosetta Stone requires you to be in front of a computer, and I needed something that I could do while driving. By the way, I recommend only attempting this on long, fairly boring freeway trips. It takes up a little too much mental bandwidth to attempt on city streets.

After studying Spanish for several months, I was able to give a technical talk in Spanish in Mexico City. Doing the talk live was terrifying, and I'll admit that my voice was shaking quite a bit. However, later I did a screencast of it, Esto es Dart. That went pretty well.

Updated: I had to disable comments because this blog post was getting too many spammy comments.


Friday, September 20, 2013

Some Random Thoughts on Haskell

It seems like all my Python friends are playing around with Haskell lately, so it's been on my mind a lot lately. Since I'm a language guy, Haskell has always fascinated me. I wrote my first article on Haskell in 2006 (Everything Your Professor Failed to Tell You About Functional Programming), and I think it's a beautiful, interesting, awe-inspiring language. However, I've never really achieved full mastery of it. Since I've been thinking about it a lot lately, I thought I'd share some of my thoughts:

  • Haskell is well known for being very concise. The functionality / lines of code ratio is very good. However, if I compare Haskell code to Python code, one thing is clear to me. Haskell squeezes in a lot more function calls per line of code than Python does. We have this idea in programming that the number of lines of code that a programmer can write in a given time period is relatively constant regardless of language. However, in my experience, I can write lines of code in Python, Ruby, and Java much more quickly than I can in Haskell. Part of this is because you can squeeze a heck of a lot more function calls into a single line in Haskell.

    It's pretty common to compare languages based on how many lines of code it takes to implement a particular algorithm. I think it'd be really interesting to compare languages based on how many symbols (such as words, operators, punctuation, significant whitespace, etc.) it takes to implement a particular algorithm. It'd also be interesting to compare languages based on their symbol / line ratio. Haskell and APL have very high symbol / line ratios. Assembly has a pretty low symbol / line ratio.

  • Some languages are easier for newbies to understand than other languages. Python and Java are easy to understand even if you don't know them. APL and Forth are impossible to understand if you don't know them. I think there are a lot of things that factor into whether a language is easy for newbies to understand. For instance, how close is the language to English? COBOL tries to be like English, so it's easy for newbies to understand. How many unusual symbols are used? APL uses a lot, so it's hard for newbies to understand. Does it follow normal, mathematical, infix notation? Forth doesn't, so it's difficult for newbies to understand. It can be difficult for newbies to understand Haskell code due to the liberal sprinkling of things like $, ., >>=, etc.

    There's also something to be said for languages that tend to use overly concise names. Consider the name creat() in C--it hurts my brain not to put an e at the end of it! Slightly more verbose names can be very helpful for newbies. If I read some Python code, and I see "threading", I have a decent idea what that is about. If I read some Haskell code, and I see "TVar", I have no clue what that is about. TVars are so incredibly interesting, but I certainly wish it had a more newbie-friendly name!

  • Haskell has fascinated me for years. However, as soon as someone mentions Category Theory to me, my eyes start to glaze over, because when it comes to programming, I am a linguist, not a mathematician. I remember Larry Wall said that he approached Perl from a linguistics point of view, and that he really liked the fact that Perl was a little messy, contextual, redundant, etc. Afterall, so is English!

    When I learn a new language, the questions that come to my mind are what's the syntax and what does the syntax do? Only after I truly appreciate the syntax and semantics can I appreciate the underlying model. For instance, I've always liked Python because of its syntax, but it took years for me to realize how cool Python was because of its "everything is dicts and functions, and you can hack stuff all you want" nature.

  • The last thing I want to cover is composability. Some languages and language features are more composable than others. For instance, it's really easy with structs, objects, algebraic data types, etc. to write something like a.b.c.d. This means an instance of A has a reference to an instance of B, which has a reference to an instance of C, etc. It's trivial to connect an object graph in this way. Functions are also very composable. In Haskell, a . b . c . d basically means a(b(c(d()))). However, monads aren't quite as trivially composable. It has taken a non-trivial amount of time for my buddy John Chee to try to explain liftM and monad transformers to me. It'll be interesting to see how all that stuff turns out.

    Of course, Haskell isn't the only language to have to worry about composability. I remember seeing a talk by one of the Scala compiler developers who said that the biggest source of bugs he had seen was from people mixing features of Scala togehter in ways that he had never considered before. Compiling each feature one at a time to work on the JVM is easy--getting all the features to play nicely with one another when they're used at the same time in unexpected ways is quite a bit harder.

So as I watch all of my friends learn Haskell, these are the things that have been on my mind. It's a fascinating language, so I always enjoy reading other people's perspectives on it!

By the way, thanks go to John Chee and Neuman Vong for patiently answering all my Haskell questions.

Wednesday, September 11, 2013

Books: Two Scoops of Django

I just finished reading the book Two Scoops of Django. It was highly recommended to me by members of the Bay Area Python Interest Group. It covers Django best practices. In short, I loved it!

It's not an introduction, tutorial, or a reference for Django. In fact, it assumes you've already gone through the Django tutorial, and it occasionally refers you to the Django documentation. Rather, it tells you what you should and shouldn't do to use Django effectively. It's very prescriptive, and it has strong opinions. I've always enjoyed books like that. Best of all, it's only about 300 pages long, so it didn't take me that long to read.

Having read the book cover-to-cover, even though I'm fairly new to Django, I kind of feel like I know what I'm doing at this point--at least a little ;) I was afraid when I started using Django that I wouldn't have that feeling until I had used it for a couple years.

So, if you're using Django, I highly recommend it!

Monday, September 09, 2013

Books: American Gods

I just finished reading American Gods. It won the Hugo, the Nebula, and the Bram Stoker award, but I read it because it was number 10 on NPR's Top 100 Science-Fiction & Fantasy Books and because my buddy Sam Rushing recommended it.

In short, I really, really liked it! I didn't think I would like it at all until about chapter 3, but after that, I couldn't put it down. It's like a mix of "O Brother Where art Thou", "The Guardians", Edgar Allan Poe, John Steinbeck, and "Pulp Fiction". My only complaint was that it was a bit too violent and sexually explicit for my tastes. Aside from that, it's a very enjoyable read.

Thursday, August 29, 2013

Python: dicts vs. classes

I like to "keep it simple stupid" when I'm coding Python. I use classes, but I don't try to shove everything into classes. When all you need is a dict or a list, use a dict or a list. However, I'm coming to think that if you have a bunch of objects that look like the following:

books = [{
  "authors": ["Neil Gaiman"],
  "title": "American Gods",
  "isbn": "9780062113450"
}]

Then it might be time to use a class rather than a dict. In this case, I'd create a class called Book, but I'd put Book instances into a simple list.

Wednesday, August 28, 2013

Python: One More Example of How PyCharm is Psychic

I had the following line in my Python code:

if self._lookup_unallocated(current_allocation_state, key) > 0:

I wanted to change it to:

unallocated = self._lookup_unallocated(current_allocation_state, key)
if unallocated > 0:

Hence, I highlighted the expression, right clicked, refactor, extract, variable. It did the refactoring and automatically guessed that I wanted to name the variable "unallocated"! Presumably, it guessed based on the name of the method I was calling. Nonetheless, it's like it read my mind!

Friday, August 23, 2013

Python: Using assertRaises as a Context Manager

If you're using the unittest library, and you want to check the value of an exception, here's a convenient way to use assertRaises:

with self.assertRaises(ValueError) as context_manager:
    call_some_function()
self.assertIn("Oops, something went wrong", str(context_manager.exception))

Thursday, August 22, 2013

Humor: Testing the Validity of Internet Email Using Perl

My wife sent me an email yesterday. It said, "What the :_&#/_&/#=;$ is he doing with a 28 year old! That is sick :-(". I wanted to test the validity of her statement, so I fed that expression into Perl. Perl ended up spitting out the first 10,000 digits of Pi. Go figure.

Monday, August 19, 2013

Books: Treading on Python

I just received my copy of Treading on Python! I was the technical editor :) There are two things that are great about this book. First, Matt Harrison's a really good Python programmer, and his writing is very crisp. Secondly, the book is really short! It's weighs in at a mere 183 pages!

So if you're reading this, Matt, congratulations, and thanks for letting me part of your book!


Tuesday, July 16, 2013

Books: Programming the Rasberry Pi: Getting Started with Python

I just finished reading Programming Raspberry Pi: Getting Started with Python. I really liked it! Actually, it was really quite amazing at how much ground Simon Monk could cover in a mere 158 pages. The whole way through, he kept things really, really simple. My favorite example of this was when he built a simple web scraper that didn't even use regular expressions, let alone an HTML or XML parser! He managed to do it using nothing more than a bunch of calls to find()! It's not what I would write as a production programmer, but as a way of getting a total newbie started? Wow!

I bought this book for my oldest three children, ages 7-11. They haven't read it yet, but I have high hopes that this will be the book that teaches them Python.

Wednesday, July 10, 2013

Use "perfect" as a verb, not as an adjective

I'm slowly making my way through the PyCon videos on pyvideo.org, and one of them that I particularly liked was Alex Martelli's "Good enough" is good enough!

He made a statement that really hit home for me. He said that we should use "perfect" as a verb, not as an adjective. That is, we should always be striving to perfect our software, without ever hoping or expecting that it will ever be perfect.

I think that's a really good message, and it applies to many parts of life. I occasionally suffer from perfectionism. That one phrase has made a profound impact on my life because I no longer worry about things that are not perfect. Rather, I am happy when I can make things slightly more perfect.

And let's not forget that Worse is Better anyway ;)

Wednesday, June 19, 2013

Twitter is Hiring Right Now

We need Scala, Java, Ruby, and Python programmers. Here is the full list of openings. If you're interested in applying, tell me which position(s) you're interested in and shoot me your resume. I'd be happy to answer any questions you have. As usual, I highly recommend the book "Cracking the Coding Interview".

Monday, June 17, 2013

Python: I Like Django

I like Django. I didn't used to. However, it's become more powerful, more flexible, and better documented since the last time I looked at it. I can now see myself really enjoying using it.

Friday, May 10, 2013

Personal: Links to My G+ and Twitter Accounts

If you enjoy my blog posts on Python, Ruby, Dart, etc., and you're looking for a new way to follow me now that Google Reader is going away, here are my Twitter and G+ accounts:

Thursday, May 09, 2013

Drawing Sierpinski's Triangle in Minecraft Using Python

In his keynote at PyCon, Eben Upton, the Executive Director of the Rasberry Pi Foundation, mentioned that not only has Minecraft been ported to the Rasberry Pi, but you can even control it with Python. Since four of my kids are avid Minecraft fans, I figured this might be a good time to teach them to program using Python. So I started yesterday with the goal of programming something cool for Minecraft and then showing it off at the San Francisco Python Meetup in the evening.

The first problem that I faced was that I didn't have a Rasberry Pi. You can't hack Minecraft by just installing the Minecraft client. Speaking of which, I didn't have the Minecraft client installed either ;) My kids always play it on their Nexus 7s. I found an open source Minecraft server called Bukkit that "provides the means to extend the popular Minecraft multiplayer server." Then I found a plugin called RaspberryJuice that implements a subset of the Minecraft Pi modding API for Bukkit servers. Next, I found this handy guide to the Minecraft Pi Protocol. Finally, I found a Python library called mcpipy that implements the Minecraft Pi Protocol in Python.

Between looking at the Minecraft Pi Protocol documentation and peeking at the mcpipy source code, it's pretty easy to figure out how to control Minecraft from Python. My next step was to figure out how to draw something cool. Naturally, the first thing to come to mind was fractals, but it's not so easy to draw most fractals with fixed sized blocks. However, Sierpinski's triangle is not so hard to draw using blocks, so that's what I did.

Here's the psuedocode for drawing Sierpinski's triangle:

draw_the_three_vertices()
current_point =
    random_point_in_triangle()
while True:
    vertex = random_vertex()
    current_point = midpoint_between(
        current_point,
        vertex)
    draw(current_point)

Here's the actual source code:
#!/usr/bine/env python

"""Draw Sierpinski's triangle in Minecraft."""

import random

import mcpi.minecraft
import mcpi.block as block
import server

# It goes from -MAX_XZ to MAX_XZ.
MAX_XZ = 128
MAX_Y = 64

# These are the vertices of the triangle. It's a list of points. Each point
# is an (X, Y, X) tuple.
TRIANGLE_HEIGHT = MAX_Y - 1
TOP = (-MAX_XZ, TRIANGLE_HEIGHT, 0)
BOTTOM_LEFT = (MAX_XZ, TRIANGLE_HEIGHT, MAX_XZ)
BOTTOM_RIGHT = (MAX_XZ, TRIANGLE_HEIGHT, -MAX_XZ)
TRIANGLE_VERTICES = [TOP, BOTTOM_LEFT, BOTTOM_RIGHT]

BASE_BLOCK_ID = block.SANDSTONE.id
TRIANGLE_BLOCK_ID = block.SNOW.id

# This is the maximum number of iterations to let the algorithm run. The
# algorithm relies on randomness, so I'm just picking a sensible value.
MAX_ITERATIONS = MAX_XZ ** 2

PRINT_FREQ = 1000


def clear_board(minecraft):
    minecraft.setBlocks(-MAX_XZ, 0, -MAX_XZ, MAX_XZ, MAX_Y, MAX_XZ, 0)
    minecraft.setBlocks(-MAX_XZ, 0, -MAX_XZ, MAX_XZ, -MAX_Y, MAX_XZ, BASE_BLOCK_ID)


def draw_sierpinski_triangle(minecraft):

    def random_in_range():
        return random.randint(-MAX_XZ, MAX_XZ)

    def int_average(a, b):
        return int(round((a + b) / 2.0))

    # Draw the triangle vertices.

    for (x, y, z) in TRIANGLE_VERTICES:
        minecraft.setBlock(x, y, z, TRIANGLE_BLOCK_ID)

    # Pick a random point to start at.

    current = (random_in_range(),
               TRIANGLE_HEIGHT,
               random_in_range())

    for i in xrange(MAX_ITERATIONS):

        if i % PRINT_FREQ == 0:
            print("Drew %s blocks" % i)

        # Pick a random vertex to "walk" toward.

        destination = random.choice(TRIANGLE_VERTICES)

        # Draw a block in the middle of the current location and the
        # destination.

        (c_x, c_y, c_z) = current
        (d_x, d_y, d_z) = destination
        current = (
            int_average(c_x, d_x),
            TRIANGLE_HEIGHT,
            int_average(c_z, d_z)
        )
        (x, y, z) = current
        minecraft.setBlock(x, y, z, TRIANGLE_BLOCK_ID)


if __name__ == "__main__":
    minecraft = mcpi.minecraft.Minecraft.create(server.address)

    # Uncomment this if you need it.
    # clear_board(minecraft)
    
    draw_sierpinski_triangle(minecraft)
The Gory Details
If you're interested, here are all the gory details.

I got all of this running on OS X 10.7.

First, you'll need Java to run Bukkit. I installed Java SE Development Kit 7u21.

Next, you need to install Bukkit. Note, you must use a version of Bukkit that is compatible with your version of the Minecraft client. For me, that meant installing the latest, development version of Bukkit. See here for more information:
mkdir -p ~/Local/bukkit_server
cd ~/Local/bukkit_server
curl -L http://dl.bukkit.org/downloads/craftbukkit/get/02122_1.5.2-R0.2/craftbukkit-dev.jar -o craftbukkit.jar
echo "cd ~/Local/bukkit_server/" > start.command
echo "java -Xms1024M -Xmx1024M -jar craftbukkit.jar -o true" >> start.command
chmod +x start.command
To start the server, execute the start.command file. To stop the server, type "stop" into the console.

Next, I installed RasberryJuice. Download the jar file and move it to ~/Local/bukkit_server/plugins. Then type "reload" in the console where Bukkit is running.

Next, you'll need to install Minecraft itself. That costs roughly $30. I put it in ~/Local. When I first ran it, it insisted on installing "Java 6". To connect to your local server, choose Multiplayer, then Direct Connect, and then enter "localhost".

To install mcpipy, you can either use Git (if you have it installed), or you can download and uncompress the zip file. I put it in ~/Local/mcpipy. To test that it's working, try:
cd ~/Local/mcpipy
python zhuowei_rainbow.py
This will draw a rainbow in your running copy of Minecraft. After running the command, assuming there were no errors, it takes a little while for the rainbow to show up.

To try out my code, create a file called ~/Local/mcpipy/jjinux_sierpinski_triangle.py with the code from above. Then run:
cd ~/Local/mcpipy
python jjinux_sierpinski_triangle.py
It'll print out messages as it draws all the blocks. This will draw Sierpinski's triangle in the sky. It takes a minute or two to show up. You can tweak the script to draw the triangle using more blocks or with a different type of block. However, I've found that making certain changes causes Bukkit to crash, so keep an eye on the console where you started Bukkit to make sure nothing bad happened. If anything bad does happen, you might want to use control-c to stop the server. Then you can delete the world, world_nether, and world_the_end directories in ~/Local/bukkit_server and restart the server.

Monday, April 29, 2013

"Await" in Python

In Guido van Rossum's PyCon 2013 keynote, he presents "a new, interoperable approach to asynchronous I/O that is being developed for inclusion in Python 3.4." Part of his proposal is a way to use "yield from" in a manner similar to await in C#. Let's just say, I'm super excited about it!


Thursday, March 14, 2013

Irrduino: A Sprinkler System Built Using Arduino, Android, Google App Engine, Python, and Dart

Cross-posted from Dart News & Updates.



Developers frequently ask me if Dart is ready for the real world. Well, of course, that depends on the application. Check out this short video in which Joe Fernandez and I not only show that Dart can be used in the real world, we also show that it can be used to take the tedium out of watering your lawn!



The Dart code for Lawnville was originally written in January of 2012, a mere three months after Dart was launched as a "technology preview". That was six months before Dart's M1 release, so it's been updated a few times along the way. However, the code really hasn't fundamentally changed that much since the beginning.

Perhaps the most interesting piece of code is the use of a Queue (from the dart:collection library) to schedule watering tasks. You can click on different parts of the lawn, and the droid will fly over and water each section for a short amount of time:
  _actionQueue = new Queue();
  ...
  _actionQueue.add({'action': 'water', 'zone': el.id});
  ...
  void _executeActionQueue() {
    if (_actionQueue.isEmpty) {
      _waitingForTimer = false;
      _idle();
    } else {
      var action = _actionQueue.removeFirst();
      _doAction(action);
      _waitingForTimer = true;
      new Timer(new Duration(milliseconds: TIMER_INTERVAL),
                _executeActionQueue);
    }
  }
A Timer and window.requestAnimationFrame are used to control animations:
  void _repositionDroid(int x, int y, [Callback callback = null]) {
    x -= (HALF * DROID_WIDTH).toInt();
    y -= DROID_HEIGHT;
    _droid.src = "/static/images/droid-jetpack-on-front.png";
    _droid.style.left = "${x}px";
    _droid.style.top = "${y}px";
    new Timer(new Duration(milliseconds: REPOSITION_DURATION), () {
      if (callback != null) {
        callback();
      } else {
        _droid.src = "/static/images/droid-waiting-front.png";
      }
    });
  }

  void _startAnimationLoop() {
    _animationStartTime = new DateTime.now().millisecondsSinceEpoch;
    window.requestAnimationFrame(_animationLoop);
  }

  void _animationLoop(int timestamp) {
    _animationProgress = timestamp - _animationStartTime;
    for (Callback callback in _animationCallbacks.values) {
      callback();
    }
    window.requestAnimationFrame(_animationLoop);
  }
An HttpRequest is used to send commands to IrrduinoServer which in turn sends commands to IrrduinoController in order to control the sprinkler system:
  void _waterRpc(int zone) {
    var req = new HttpRequest();
    int secs = (TIMER_INTERVAL * SECS_PER_MS).toInt();
    req.open("POST", "/?water-zone=true&zone=${zone}&secs=${secs}", true);
    req.onReadyStateChange.listen((Event e) {
      if (req.readyState == 4) {
        if (req.status == 200) {
          window.console.log("Watering was successful");
        } else {
          window.console.log("Watering was unsuccessful");
        }
      }
    });
    req.send();
  }
In total, the complete Dart code is about 110 lines long, not counting comments and closing braces.

You might wonder why I chose to use Dart so soon after its release, especially since I wasn't even on the Dart team at the time. I've always gotten a kick out of coding in new languages. At the time, I figured that as long as I could talk to the DOM and make XMLHttpRequests, I could do almost anything. These days, Dart is a lot more useful thanks to the growing selection of pub packages available, but even before these things existed, Dart had enough functionality to help water a lawn ;)

If you want to download the complete source code for Irrduino, you can get it from bit.ly/waterjoeslawn.

Wednesday, February 27, 2013

Dart on a Chromebook: Success!

I finally have a viable approach to editing Dart directly on a Chromebook running ChromeOS! The usual approach to developing Dart code on a Chromebook is to use Chrome Remote Desktop to connect to another development machine. However, I wanted an approach that would let me develop in Dart while offline, for instance if I'm giving a talk on Dart and my internet connection goes down.

Crouton is a set of scripts based around debootstrap that bundle up into an easy-to-use, Chromium OS-centric Ubuntu chroot generator. Using Crouton, I was able to create a chroot running a basic Ubuntu setup. Within the chroot, I was able to install a JDK and then Dart Editor. Everything works, as you can see in the picture. I can switch back and forth between XFCE and ChromeOS's desktop using a key combination, and everything still runs at native speed since it's just a simple chroot.

I got everything working on my wife's Samsung Series 5 Chromebook running an Intel Atom processor. I have a newer ARM-based Chromebook, but there is currently no ARM port of the Dart VM. I used the 32-bit version of the JDK and the 32-bit version of Dart Editor.

I'm pretty excited that this works because this is one of the few things that was preventing me from fully switching to a Chromebook :) Now, all I need to do is get my hands on a Chromebook Pixel!

Tuesday, February 19, 2013

Dart with Google Web Toolkit

Cross-posted from Dart News & Updates.

In this episode of Dartisans, I'm going to show you a variety of ways to use Dart with Google Web Toolkit. I know that there are a lot of GWT developers out there who would like to give Dart a shot, but they aren't sure how because they already have a large, successful app that's written in GWT. I'm going to show you ways to integrate Dart into your existing GWT application without having to rewrite it from scratch.

To do this, I've built a sample application that uses both GWT and Dart. I'll show you how to setup a development environment so that you can work with both technologies. Then, I'll show you a variety of ways in which you can get GWT and Dart to interoperate, such as:
  • Using GWT and Dart to manage different parts of the same page
  • Using Dart to retrieve JSON from a Java servlet
  • Using window.postMessage and JSNI to pass messages between GWT and Dart
  • Using JavaScript, JSNI, and Dart's js package for synchronous interoperability between GWT and Dart
  • Using CustomEvent objects and Elemental to pass messages between GWT and Dart
Rather than show you a one-size-fits-all solution, I decided to show you a bunch of approaches so that you could pick the right tool for the job. Each of them has stengths and weaknesses, and I'll cover those along the way as well.

Aside from watching the video, you can also download the source code or view the video transcript.



As always, we invite you to join the discussion on the Dart mailing list, and ask us questions on Stack Overflow. Your feedback is important. Thanks for checking out Dart!

Thursday, February 14, 2013

Personal: My Buddy is Looking for a Python Job


I have a buddy named Jeff Stewart who just graduated from St. Mary's College of California, which is where I'm from. He's fresh out of school and looking for his first programming job. He knows Python, Java, C++, etc. Here's his resume. I've code reviewed his code; he's smart, careful, and hard working.

Tuesday, January 22, 2013

Dart: My Experience Porting to Library v2

Updated: January 25, 2013: I ported the rest of my code. Hence, I updated the list below.

I ported all of my code to Dart lib v2. Here's what I had to do to get all of my projects to work:

  • Timer is now in 'dart:async', not 'dart:isolate'.
  • Element.elements is now Element.children.
  • LocalWindow is now Window.
  • window.webkitRequestFileSystem is now window.requestFileSystem.
  • Completer.completeException is now Completer.completeError.
  • Future.handleException is now Future.catchError. Furthermore, it no longer receives a "bare" exception object. It receives an AsyncError object. Use AsyncError.error to get the original exception object.
  • You have to use .then() and .catchError() in a single chain such as produceFuture().then((value) => null).catchError((e) => null). If you do this as two separate calls on the same future, the wrong thing will happen.
  • innerHTML is now innerHtml.
  • window.webkitNotifications is now window.notifications.
  • Map.keys and Map.values return iterators, not lists. This might break your code even if there are no static warnings. If you need a real list, call .toList() on the iterator.
  • BiquadFilterNode.type now takes a string such as "lowpass" instead of an int such as 0 or LOWPASS. I created a bug (http://code.google.com/p/dart/issues/detail?id=8119) to change that to a string.
  • AudioBufferSourceNode, BiquadFilterNode, etc. have connect and disconnect methods that have input and output parameters. It used to be acceptable to pass null for those parameters. To get the same behavior now, you must pass 0. You will not get a static warning if you don't update your code. It'll fail at runtime.
  • FileReader.readAsDataURL is now FileReader.readAsDataUrl.
  • StringBuffer.add no longer returns the StringBuffer. Use method cascades instead.
  • new Path.fromNative is now just new Path.
  • Iterable.some is now Iterable.any.
  • Iterable.map is now Iterable.mappedBy.
  • Future.chain is now Future.then.
  • Change "import 'dart:json'" to "import 'dart:json' as JSON" since there is no
  • JSON class anymore.

There are lots of other things that have changed, but those are the things that I got hit with.

Monday, January 07, 2013

Esto es Dart

Cross-posted from Dart News & Updates.

This is a blog post for Spanish-speaking developers who may be interested in learning Dart. Please pass it along to any Spanish-speaking developers you know!

En su libro El programador pragmático, David Thomas y Andrew Hunt recomiendan "aprender al menos un lenguage nueva cada año." Bueno, es un nuevo año, y creo que ahora es un buen momento para aprender un nuevo lenguage. De hecho, si usted todavía no ha aprendido Dart, no hay mejor momento!

El año pasado, empecé a estudiar español para poder compartir con todos los hispanohablantes del mundo mi introducción a Dart traducido al español. Después de pasar dos días delante de un micrófono tratando de no sonar como si tuviera canicas en mi boca, les presento a Esto es Dart! Espero que les guste.

In English:

In their book The Pragmatic Programmer, David Thomas and Andrew Hunt recommend that you "learn at least one new language every year." Well, it's a new year, and now's a great time to learn a new language. In fact, if you haven't learned Dart yet, there's no better time!

Last year, I started studying Spanish so that I could reach out to all the Spanish speakers of the world with my introduction to Dart translated to Spanish. After spending two days in front of a microphone trying not to sound like I have marbles in my mouth, I present to you Esto es Dart! I hope you enjoy it.



Thursday, January 03, 2013

More Dart HTML5 Goodness

Cross-posted from Dart News & Updates.

dart-html5-samples is a collection of HTML5 samples written in Dart. Most of them were ported from HTML5 Rocks. I first blogged about dart-html5-samples about three months ago. Since then, a ton of cool, new HTML5 samples have been ported to Dart, and we've updated all the samples for M2!

Here is the current list of samples:

There are a couple samples that I want to point out because they're so interesting. Adam Singer ported Eric Bidelman's terminal sample. Try clicking near the cursor and typing help. Here's the source.

John McCutchan, who clearly has a background in video gaming, ported his Pointer Lock And First Person Shooter Controls sample to Dart. Here's the source.

Special thanks go to Adam Singer, Shailen Tuli, John McCutchan, and Jason Brooks for their help on the project. If you're interested in contributing new HTML5 samples, check out the README for how to get started! As always, if you’d like to chat more about this, feel free to send us email on the mailing list or ask questions on Stack Overflow.