On the USB sticks

  1. Dart Editor
  2. Bullseye CodeLab notes
  3. Codelab source code (zip file)
blogger-with-dart.appspot.com

Blogger with Dart

Brett Morgan

blogger-with-dart.appspot.com

Agenda

  1. Get Set Up
  2. Introduction to Dart
  3. Bullseye Codelab
  4. Lunch
  5. Introduction to Blogger APIs
  6. Blogger Codelab

Tools

Download new Editor builds frequently.
Tip

Language overview

Your first program

main() {
  print('Hello, Dart!');
}
Try it out!

Variables - optional typing

You are free to declare types of variables. Or not.

var hitPoints = 25;
int hitPointsInt = 25;

if (hitPoints === hitPointsInt) {
  print("They are the same.");
} else {
  print("Oooh different!");
}
Try it out!

Variables - finals don't change

final can't be changed after initialization

final Date birthDate = new Date.fromString('2011-04-23 12:00:00Z');
birthDate = new Date.now();

print("birthDate = $birthDate");
Try it out!

Variables - initialised with null

Date birtDate;
String name;

print("$name's birthDate is $birthDate");
				
Try it out!

String

String interpolation

Person person = new Person("Bob");
String to = "Bazza";

String greeting = 'Hello, ${person.name}!';
String greeting2 = "Hello, $to.";
Try it out!

Multi-line strings

String html = """
<tr>
  <td>$amount</td>
  <td>$dueDate</td>
</tr>
""";
				
Try it out!

Raw strings

String regularExpression = @"(\w+)";
String targetString = "Parse my string";

RegExp exp = new RegExp(regularExpression);  
Iterable matches = exp.allMatches(targetString);
Try it out!

Numbers

Boolean

if (1) { 
  print('true'); 
} else { 
  print('false!'); 
}
Try it out!

(Note: above will fail in checked mode, 1 is not a bool)

List Growable or fixed size

// fixed size of 2
var candyBars = new List(2);

candyBars.add('snickers'); // ERROR, can't add to fixed size
candyBars[0] = 'snickers'; // OK
Try it out!

List as Literal, or new'ed up

var fruitsLiteral = [];
List fruitsWithNew = new List();
fruitsLiteral.add('oranges');
fruitsWithNew.add('apples');
Try it out!

Map

// Map literal
// keys are strings
var sites = {};

// or when using constructor,
// keys are Hashable
var map = new Map();

map['dart'] = 'http://www.dartlang.org';
print(map.containsKey('pascal')); // false
Try it out!

Set

var fruits = new Set();

fruits.add('apples');
fruits.add('oranges');
fruits.add('apples');

print(fruits.length); // 2	
Try it out!

Collection

Dynamic type

yell(msg) {
  return '$msg !!!!';
}

// same as

Dynamic yell(Dynamic msg) {
  return '$msg !!!';
}

Checking the type

('hello' is String) == true;

(4 is! String) == true;

(4 is int) == true;

(4 is Dynamic) == true;
Use types, at least for the "surface area" of your code.
Tip

Equality (today)

Try it out!

Equality (soon)

Functions

Functions

say(msg) {
  print('$msg Pass it on.');
}

// assign to variable
var speak = say;

// use anonymous functions
var yell = (msg) {
  speak('$msg!!!');
};

yell('Dart is here'); // Dart is here!!! Pass it on.
Try it out!

Optional parameters

say(msg, [via]) {
  if (via != null) {
    print('$msg sent by $via');
  } else {
    print(msg);
  }
}

say('howdy'); // howdy

say('howdy', 'smoke signals'); // howdy sent by smoke signals
Try it out!

Named parameters

say(msg, [via]) {
  if (via != null) {
    print('$msg sent by $via');
  } else {
    print(msg);
  }
}

say('hello', via:'tin can and string');
Try it out!

Default parameter values

say(msg, [via = 'first class']) {
  print('$msg sent by $via');
}

say('howdy'); // howdy sent by first class
Try it out!

Lexical closures

Function makeAdder(num n) {
  return (num i) => n + i;
}

main() {
  var add2 = makeAdder(2);
  print(add2(3)); // 5
}
Try it out!

Nested functions

main() {
  loudify(msg) {
    var megaPhone = new MegaPhone();
    megaPhone.enable();
    return megaPhone.amplify(msg);
  }
  print(loudify("Howdy"));
}
Try it out!

Dart's runtime modes

Production mode

Checked mode

Enabling dynamic type assertions

Turn on checked mode in editor

Dynamic type errors

bar(num n) { return n * 2; }

bar(3.2); // works fine

int i_bar(num n) { return n * 2; }

i_bar(3.2); // FAILS in checked mode
            // because returned value is not an int

Static checker

String s1 = '9';
String s2 = '1';
…
int n = s1 + s2; // Static checker generates WARNING!!
print(n);
Try it out!
Use checked mode during development.
Tip

Control flow

If and else

if (isRaining()) {
  you.bringRainCoat();
} else if (isSnowing()) {
  you.wearJacket();
} else {
  car.putTopDown();
}
Try it out!

For loops

main() {
  var callbacks = [];
  for (var i = 0; i < 2; i++) {
    callbacks.add(() => print(i));  // closure around the value of i
  }
  callbacks.forEach((c) => c());
}

// prints 0 then 1 in proper dart
// prints 2 twice on try.dartlang.org

forEach in Collection

candidates.forEach((candidate) => candidate.interview());
Try it out!

for in

var collection = [0, 1, 2];
for (var x in collection) {
  print(x);
}
Try it out!

while and do while

while (!auctionItem.currentWinner(bidder) &&
    auctionItem.currentBid < bidder.maximumBid) {
  auctionItem.placeBid(bidder, auction.currentBid + 1);
}
do {
  printLine();
} while (!atEndOfPage());

switch and case

var command = 'OPEN';
switch (command) {
  case 'OPEN':
    executeOpen();
    // ERROR: missing break causes an exception to be thrown!!

  case 'CLOSE':
    executeClose();
    break;
}
Try it out!

switch and case - empty case falls through

var command = 'CLOSED';
switch (command) {
  case 'CLOSED':     // empty case falls through
  case 'NOW_CLOSED':
    // runs for both CLOSED and NOW_CLOSED
    executeClose();
    break;
}

try catch finally

Throw an Exception, or any object

buyMoreLlamas() {
  if (llamas.isEmpty()) {
    throw new OutOfLlamasException();
  }
  …
}

try {
  buyMoreLlamas();
} catch(final OutOfLlamasException e) {
  print("Buy more llamas!: $e");
} catch(final e) {
  print(e); // catch-all
} finally {
  cleanUpLlamaPens();
}
Try it out!

try finally

try {
  rayTraceScene();
} finally {
  cleanUpTempDir();
}

try catch

try {
  rayTraceScene();
} catch(final InvalidSceneDescription e) {
  upgradeSceneDescriptionFormat();
}

Assertions

positiveRange(lower, upper) {
  assert(lower > 0);
  assert(upper > lower);
  var range = new List(upper+1-lower);
  for (var i = 0; lower <= upper; i++) {
    range[i] = lower++;
  }
  return range;
}

main() {
	positiveRange(2, 2);
}


Unhandled exception:
'file:///Users/brettmorgan/dart/loudify/loudify.dart': Failed assertion: line 3 pos 10: 'upper > lower' 
is not true.
Try it out!

Exercise: FizzBizz

  1. In try.dartlang.org write a program that prints 1 to 20.
  2. Alter it to print out "fizz" for numbers divisible by 3.
  3. Alter it again, to print out "buzz" for numbers divisible by 5.
  4. Print "FizzBuzz" for numbers divisible by both...

Advanced exercise: figure out how this works...

Bullseye Codelab

Evented IO with dart:io

#import('dart:io');

main() {
  print('start of main');
  new Timer(1000, (Timer t) => print('timer'));
  print('end of main');
}

Serving web traffic

A web server that responds "Hello, world" to everything.

#import('dart:io');

main() {
  var server = new HttpServer();
  server.listen('127.0.0.1', 8080);
  server.onRequest = (HttpRequest request, HttpResponse response) {
    response.outputStream.write('Hello, world'.charCodes());
    response.outputStream.close();
  };
}

Exercise: Building a WebServer

#import('dart:io');
#import('dart:uri');

main() {
  HttpServer server = new HttpServer();

  server.listen('127.0.0.1', 8080);
  server.onRequest = …;
}
Clone-able starting point on Github

File IO

The following code will print it's own source code

#import('dart:io');

main() {
  var options = new Options();
  var file = new File(options.script);
  file.readAsText(Encoding.ASCII, (text) => print(text));
}

Exercise: Building a WebServer, Part 2

Take the previous WebServer, add a request dispatcher and the ability to serve static files.

For bonus points: proxy another webserver, e.g. an RSS Feed.

void serveFile(String path, String contentType, HttpResponse response) {
  log("Serving $path for $contentType");
  InputStream input = new File(path).openInputStream();
  OutputStream output = response.outputStream;
  response.headers['Content-Type'] = contentType;

  input.onData = …;

  input.onClosed = …;
}
Clone-able Starting Point

Querying the DOM

This should look familiar to people who use jQuery.

elem.query('#foo');
elem.queryAll('div');
elem.queryAll('[name="foo"]');
elem.queryAll('.foo');
elem.query('.foo .bar');
elem.queryAll('.foo .bar');

Note .query returns Element, while .queryAll returns List<Element>.

Adding event handlers and modifying styles

elem.on.click.add((event) => print('click!'));
elem.on.click.remove(listener);

elem.style.border = "solid";
elem.style.borderRadius = "5px";
elem.style.borderColor = "#00aa00";

Note the use of function literals for click handlers.

Exercise: Playing in the DOM

#import('dart:html');

void main() {
  document.query('#status').innerHTML = "Hello World!";
}
Clone-able starting point

Dart Online resources

Language tour site Language tour
Dart API docs site API Docs
Synonyms from JavaScript to Dart site Synonyms from JavaScript to Dart
Dart style guide page Dart style guide
Idiomatic Dart page Idiomatic Dart
Dart News & Updates site Dart News & Updates
Search the Dartiverse page Search the Dartiverse

Dart team loves feedback!

Introduction to Blogger APIs

TMTOWTDI

Blogger GData API

Blogger JSON API

Blogger's Data Model

Exploring the API

Limitations

Exercise: Glue the server and the client together

Open Hacking Time!

Thanks!

Backup Slides

Classes

Instance variables

class Point {
  var x, y;
}

var p = new Point();
p.x = 2;    // setter
p.y = 4;
print(p.x); // getter

Instance variable initialization in class body

class Point {
  var x = 0,   // OK, int literals are compile time constants
      y = 0;
}

class Game {
  var player = new Player();  // ERROR, not a compile time constant
}

// instead

class Game {
  var player;
  Game() {
    player = new Player();
  }
}

Static class variables

class Colors {
  static final RED = 'red';
  static final GREEN = 'green';
}

Superclass

class Person {
  String name;
  String toString() {
    return name;
  }
}

class Employee extends Person {
  String company;
  String toString() {
    return '$name works at $company';
  }
}

var emp = new Employee();
emp.name = 'Alice';
emp.company = 'Google';
print(emp);  // Alice works at Google

Superclass constructors

class A {
  A() {
    print("A");
  }
}

class B extends A {
  B() {
    print("B");
  }
}

void main() {
  var b = new B(); // prints A then B
}

Constructors

class Point {
  var x, y;
  Point(this.x, this.y);
}

var p = new Point(2, 4);

print(p.x); // 2

Initializers list

class Point {
  final num x;
  final num y;
  final num distanceFromOrigin;

  Point(x, y) :
    x = x,
    y = y,
    distanceFromOrigin = calcDistance(x, y) {
      // do other setup now that this exists
  }

  static calcDistance(x, y) {
   Math.sqrt((x*x) + (y*y));
  }
}

Named constructors

class DomElement {
  DomElement.tag(String tagName) { ... }
  DomElement.html(String html) { ... }
}

var button = new DomElement.tag("button");
Use named constructors for more readable code.
Tip

Operator "overloading"

class Point {
  final num x, y;
  Point(this.x, this.y);
  Point operator +(Point other) {
    return new Point(x+other.x, y+other.y);
  }
}

void main() {
  var p1 = new Point(1, 2);
  var p2 = new Point(2, 2);

  var p3 = p1 + p2;

  print(p3.x); // 3
}

Getters and setters

// initially

class Person {
  num age;
  Person(this.age);
}

print(new Person(21).age);  // 21

// after refactoring

class Person {
  Date birthdate;
  Person(this.birthdate);

  num get age() {
    return (new Date.now().difference(birthdate).inDays / 365).toInt();
  }
}

var p = new Person(new Date.fromString('1991-01-01 12:00:00Z'));
print(p.age);  // 21

This is this

#import('dart:html');

class Awesome {

  Awesome(Element button) {
    button.on.click.add((e) => cool());  // call cool() from this
  }

  cool() {
    window.alert("inside Awesome.cool");
  }

}

Generics

Generics

new List<String>() is List<Object>   // true: every string is an object 
new List<Object>() is! List<String>  // true: not all objects are strings
new List<String>() is! List<int>     // true: strings are not ints
new List<String>() is List           // true

Mixing generics and non-generics

class Card {
  …
}

interface CardDatabase {
  saveCard(Card card);
  List allCards();
  List cardsByYear(int year);
  …
}

Mixing generics and non-generics, cont.

// your code
main() {
  var cards = new CardDatabaseImpl();
  List<Card> myCollection = cards.allCards();
}

Mixing generics and non-generics, cont.

List<Card> is List

Upper bounds

class HashMap<K extends Hashable, V> implements Map {
…
}
Add generics to your typed code for better code completion and static analysis.
Tip
Learn more about Dart's generics in articles by Gilad Bracha and Eli Brandt.
Tip

Interfaces

Interfaces

interface Handler {
  static final SUCCESS = 1;
  static final FAILURE = 0;

  onSuccess(Event e);

  onFailure(Event e);
}

Super interfaces

interface SocketHandler extends Handler {

  onOpen(Event e);

  onClose(Event e);

}

Default class

		interface Cache<String, V> default MemoryCache {
		  Cache();
		  V operator [](String key);
		  void operator []=(String key, V value);
		}

		class MemoryCache<String, V> implements Cache {
		  ...
		}

		Cache cache = new Cache();   // constructs a new MemoryCache
		

Summary

Dart is familiar

Dart is scalable

Dart adds compelling features

Dart has two runtime modes