Kasper Lund
Seth Ladd
Chrome Dev Summit 2013
#dartlang
#dartlang
1.0
Stability you can count on.
#dartlang
Lightning Tour
#dartlang
class Hug {
Simple syntax, ceremony free
Familiar
#dartlang
class Hug {
num strength;
Hug(this.strength);
Simple syntax, ceremony free
Terse
#dartlang
class Hug {
num strength;
Hug(this.strength);
Hug operator +(Hug other) {
return new Hug(strength + other.strength);
}
Simple syntax, ceremony free
Operator overriding
#dartlang
class Hug {
num strength;
Hug(this.strength);
Hug operator +(Hug other) {
return new Hug(strength + other.strength);
}
void patBack({int hands: 1}) {
// ...
}
Simple syntax, ceremony free
Named, optional params w/ default value
#dartlang
// ...
Hug operator +(Hug other) {
return new Hug(strength + other.strength);
}
void patBack({int hands: 1}) {
// ...
}
String toString() => "Embraceometer reads $strength";
}
Simple syntax, ceremony free
One-line function
#dartlang
// ...
Hug operator +(Hug other) {
return new Hug(strength + other.strength);
}
void patBack({int hands: 1}) {
// ...
}
String toString() => "Embraceometer reads $strength";
}
Simple syntax, ceremony free
String Interpolation
#dartlang
Clean semantics and behavior
#dartlang
Clean semantics and behavior
Examples:
#dartlang
"hello".missing // ??
Missing getter?
Class 'String' has no instance getter 'missing'.
NoSuchMethodError : method not found: 'missing'
Receiver: "hello"
Arguments: []
Logical
#dartlang
'hello' > 1 // ??
String compared to number?
Class 'String' has no instance method '>'.
Logical
#dartlang
var foo = 'top-level';
main() {
if (true) { var foo = 'inside'; }
print(foo); // ?? What will this print?
}
Variable scope?
top-level
Logical
No hoisting
#dartlang
class AwesomeButton {
AwesomeButton(button) {
button.onClick.listen((Event e) => this.atomicDinosaurRock());
}
atomicDinosaurRock() {
/* ... */
}
}
Scope of this?
Lexical this
#dartlang
library games;
import 'dart:math';
import 'players.dart';
class Darts {
// ...
}
class Bowling {
// ...
}
Player findOpponent(int skillLevel) {
// ...
}
Scalable structure
Functions
Classes
Libraries
Packages
Mixins
Interfaces
#dartlang
Compiling to JavaScript
#dartlang
Our goals
#dartlang
We need an optimizing compiler
function inlining
loop-invariant code motion
type propagation
global value numbering
redundant load elimination
dead code elimination
… and much, much more!
#dartlang
Simple Dart method
main() {
var p = new Point(2, 3);
var q = new Point(3, 4);
var distance = p.distanceTo(q);
...
}
#dartlang
… compiles to simple JavaScript
main: function() {
var p, q, distance;� p = new Point(2, 3);� q = new Point(3, 4);� distance = p.distanceTo$1(q);
...�}
#dartlang
… compiles to simple JavaScript
main: function() {
var p, q, distance;� p = new Point(2, 3);� q = new Point(3, 4);� distance = p.distanceTo$1(q);
...�}
arity is encoded in method name
#dartlang
Tree shaking
main
Library
baz
foo
bar
boo
imports
calls
baz
main
foo
bar
dart2js
#dartlang
Two-level tree shaking
Resolver queue
Parser
Resolver
Compilation queue
Builder
Code generator
Emitter
File reader
Diet parser
#dartlang
DeltaBlue
Constraint solving algorithm
#dartlang
DeltaBlue: Constraint solver
#dartlang
DeltaBlue: Working with constraints
void addConstraintsConsumingTo(Variable v, List<Constraint> coll) {
Constraint determining = v.determinedBy;
for (int i = 0; i < v.constraints.length; i++) {
Constraint c = v.constraints[i];
if (c != determining && c.isSatisfied()) {
coll.add(c);
}
}
}
#dartlang
Same semantics without types
addConstraintsConsumingTo(v, coll) {
var determining = v.determinedBy;
for (var i = 0; i < v.constraints.length; i++) {
var c = v.constraints[i];
if (c != determining && c.isSatisfied()) {
coll.add(c);
}
}
}
#dartlang
DeltaBlue: Unoptimized
addConstraintsConsumingTo$2: function(v, coll) {
var determining, t1, t2, t3, i, t4, c;
determining = v.get$determinedBy();
t1 = v.constraints;
t2 = getInterceptor$as(t1);
t3 = getInterceptor$a(coll);
i = 0;
while (true) {
t4 = t2.get$length(t1);
if (typeof t4 !== "number") throw new IllegalArgumentError(t4);
if (!(i < t4)) break;
c = t2.$index(t1, i);
if ((c == null ? determining != null : c !== determining) && c.isSatisfied$0() === true) {
t3.add$1(coll, c);
}
++i;
}
}
Simply not good enough!
#dartlang
DeltaBlue: Number checks
addConstraintsConsumingTo$2: function(v, coll) {
...
while (true) {
t4 = t2.get$length(t1);
if (typeof t4 !== "number") throw new IllegalArgumentError(t4);
if (!(i < t4)) break;
...
but we want to compare it against one
we don’t know length is a number
so we have to explicitly check
#dartlang
Our challenge ...
clean semantics and unsurprising behavior
without
extra checks when compiled to JavaScript
#dartlang
Global optimizations
#dartlang
Global optimizations
#dartlang
Inferring types iteratively
main() {
foo(42);
}
foo(x) {
bar(x);
}
bar(y) {
if (y is String) print(y);
else foo(“$y”);
}
bar is called with a string
foo is called with an int
bar is called with an int
foo is called with a string
print is called with a string
#dartlang
Inferring types iteratively
main() {
foo(42);
}
foo(x) {
bar(x);
}
bar(y) {
if (y is String) print(y);
else foo(“$y”);
}
x :: int | String
y :: int | String
#dartlang
DeltaBlue
addConstraintsConsumingTo(v, coll) {
var determining = v.determinedBy;
for (var i = 0; i < v.constraints.length; i++) {
var c = v.constraints[i];
if (c != determining && c.isSatisfied()) {
coll.add(c);
}
}
}
#dartlang
Global type inference in action
addConstraintsConsumingTo(v, coll) {
var determining = v.determinedBy;
for (var i = 0; i < v.constraints.length; i++) {
var c = v.constraints[i];
if (c != determining && c.isSatisfied()) {
coll.add(c);
}
}
}
Array<subclass=Constraint>
null | exact=Variable
#dartlang
Global type inference in action
addConstraintsConsumingTo(v, coll) {
var determining = v.determinedBy;
for (var i = 0; i < v.constraints.length; i++) {
var c = v.constraints[i];
if (c != determining && c.isSatisfied()) {
coll.add(c);
}
}
}
v :: null | exact=Variable
coll :: Array<subclass=Constraint>
v.determinedBy :: null | subclass=Constraint
v.constraints :: Array<subclass=Constraint>
v.constraints.length :: int
v.constraints[i] aka c :: subclass=Constraint
c.isSatisfied() :: bool
#dartlang
Output without type inference
addConstraintsConsumingTo$2: function(v, coll) {
var determining, t1, t2, t3, i, t4, c;
determining = v.get$determinedBy();
t1 = v.constraints;
t2 = getInterceptor$as(t1);
t3 = getInterceptor$a(coll);
i = 0;
while (true) {
t4 = t2.get$length(t1);
if (typeof t4 !== "number") throw new IllegalArgumentError(t4);
if (!(i < t4)) break;
c = t2.$index(t1, i);
if ((c == null ? determining != null : c !== determining) && c.isSatisfied$0() === true) {
t3.add$1(coll, c);
}
++i;
}
}
526 characters
v :: null | exact=Variable
#dartlang
With type inference (1)
addConstraintsConsumingTo$2: function(v, coll) {
var determining, t1, t2, t3, i, t4, c;
determining = v.determinedBy;
t1 = v.constraints;
t2 = getInterceptor$as(t1);
t3 = getInterceptor$a(coll);
i = 0;
while (true) {
t4 = t2.get$length(t1);
if (typeof t4 !== "number") throw new IllegalArgumentError(t4);
if (!(i < t4)) break;
c = t2.$index(t1, i);
if ((c == null ? determining != null : c !== determining) && c.isSatisfied$0() === true) {
t3.add$1(coll, c);
}
++i;
}
}
v.constraints :: Array<subclass=Constraint>
#dartlang
With type inference (2)
addConstraintsConsumingTo$2: function(v, coll) {
var determining, t1, t2, t3, i, t4, c;
determining = v.determinedBy;
t1 = v.constraints;
t2 = getInterceptor$as(t1);
t3 = getInterceptor$a(coll);
i = 0;
while (true) {
t4 = t1.length;
if (typeof t4 !== "number") throw new IllegalArgumentError(t4);
if (!(i < t4)) break;
c = t1[i];
if ((c == null ? determining != null : c !== determining) && c.isSatisfied$0() === true) {
t3.add$1(coll, c);
}
++i;
}
}
v.constraints.length :: int
#dartlang
With type inference (3)
addConstraintsConsumingTo$2: function(v, coll) {
var determining, t1, , t3, i, , c;
determining = v.determinedBy;
t1 = v.constraints;
t3 = getInterceptor$a(coll);
i = 0;
while (true) {
if (!(i < t1.length)) break;
c = t1[i];
if ((c == null ? determining != null : c !== determining) && c.isSatisfied$0() === true) {
t3.add$1(coll, c);
}
++i;
}
}
condition is now simple enough to be an expression so we turn this into a for-loop
#dartlang
With type inference (4)
addConstraintsConsumingTo$2: function(v, coll) {
var determining, t1, t3, i, c;
determining = v.determinedBy;
t1 = v.constraints;
t3 = getInterceptor$a(coll);
for (i = 0; i < t1.length; ++i) {
c = t1[i];
if ((c == null ? determining != null : c !== determining) && c.isSatisfied$0() === true) {
t3.add$1(coll, c);
}
}
}
33% smaller than original JS output
coll :: Array<subclass=Constraint>
#dartlang
With type inference (5)
addConstraintsConsumingTo$2: function(v, coll) {
var determining, t1, , i, c;
determining = v.determinedBy;
t1 = v.constraints;
for (i = 0; i < t1.length; ++i) {
c = t1[i];
if ((c == null ? determining != null : c !== determining) && c.isSatisfied$0() === true) {
coll.push(c);
}
}
}
t1 can be initialized in for-loop
#dartlang
With type inference (6)
addConstraintsConsumingTo$2: function(v, coll) {
var determining, t1, i, c;
determining = v.determinedBy;
for (t1 = v.constraints, i = 0; i < t1.length; ++i) {
c = t1[i];
if ((c == null ? determining != null : c !== determining) && c.isSatisfied$0() === true) {
coll.push(c);
}
}
}
41% smaller than original JS output
c :: subclass=Constraint (not null)
#dartlang
With type inference (7)
addConstraintsConsumingTo$2: function(v, coll) {
var determining, t1, i, c;
determining = v.determinedBy;
for (t1 = v.constraints, i = 0; i < t1.length; ++i) {
c = t1[i];
if (c !== determining && c.isSatisfied$0() === true) {
coll.push(c);
}
}
}
48% smaller than original JS output
c.isSatisfied() :: bool
#dartlang
With type inference (8)
addConstraintsConsumingTo$2: function(v, coll) {
var determining, t1, i, c;
determining = v.determinedBy;
for (t1 = v.constraints, i = 0; i < t1.length; ++i) {
c = t1[i];
if (c !== determining && c.isSatisfied$0()) {
coll.push(c);
}
}
}
50% smaller than original JS output
#dartlang
DeltaBlue: Fully optimized
addConstraintsConsumingTo$2: function(v, coll) {
var determining, t1, i, c;
determining = v.determinedBy;
for (t1 = v.constraints, i = 0; i < t1.length; ++i) {
c = t1[i];
if (c !== determining && c.isSatisfied$0()) {
coll.push(c);
}
}
}
262 characters, same semantics
#dartlang
Performance
#dartlang
Workflow
#dartlang
Develop
w/ Dartium,
fast iterations.
The Cloud ™
upload build/ dir
Final testing
Testing on production browsers
dart2js
Tree shaking + minification
+ concatenation
JS
pub build
Smaller than some CSS frameworks
#dartlang
Ready to get started? Write a Dart app!
dartlang.org/codelabs/darrrt/
#dartlang
Dart 1.0 for the modern web
#dartlang
WARNING:
Secret Google info beyond this point
#dartlang