Wednesday, February 29, 2012

Dart buildbot now publicly available

Posted by Rico Wind

The Dart buildbot is now publicly available at http://buildbot.dartlang.org.


You can see the build status of projects like the VM, Editor, and Dartium.

Enjoy!

Tuesday, February 28, 2012

Static variable initialization opened up to any expression

Posted by Gilad Bracha


(Follow along with the original thread titled Lazy initialization of statics from the mailing list.)


In Dart static variables may only be initialized with compile-time constants (hereafter referred to as just constants in the interest of brevity).  Static variables include all top-level variables as well as static variables of classes. The motivation is our desire to avoid costly initialization (and attendant slowness) at program startup. However, the requirement to use constants is quite restrictive.

We plan on relaxing the restrictions on initialization of statics while still avoiding high latency at startup by making the initialization lazy. We can evaluate the initializer at first use rather than at library or class load time.

We are aware that the interaction of laziness and imperative programming is problematic, because results are timing dependent. Currently this is a non-issue because the initializers evaluate constants, which are timing-independent.

Nevertheless, lifting the restriction that statics be initialized is a clear win, and has have no semantic effect on currently legal programs. Code that relies on side-effects in initialization could behave in surprising ways, but order dependent initialization is a bad idea and should be avoided in any case.

Below are the relevant spec changes. For speakers of English, the executive summary is:


You will be able to use any expression (not just constant expressions) to initialize a static variable (including top level variables). The initialization will be carried out upon the first invocation of the getter of that variable (aka first read). If the initialization throws an exception, the variable will be set to null, and the exception will be propagated.



Specification Changes


As usual, changes highlighted in yellow.

Variables

Variables are storage locations in memory.  

variableDeclaration:
     declaredIdentifier (',' identifier)*
   ;
initializedVariableDeclaration:
     declaredIdentifier ('=' expression)? (',' initializedIdentifier)*
   ;
initializedIdentifierList:
     initializedIdentifier (',' initializedIdentifier)*
   ;
initializedIdentifier:
     identifier ('=' expression)?
   ;


declaredIdentifier:
     finalVarOrType identifier
   ;



finalVarOrType:
     final type?
   |
var    | type
   ;




A variable that has not been initialized has the initial value null.
A final variable is a variable whose declaration includes the modifier final. A final variable can only be assigned once, when it is initialized, or a compile-time error occurs.

A static variable is a variable that is not associated with a particular instance, but rather with an entire library or class.  

Static variable declarations are initialized lazily. The first time a static variable v is read, it is set to the result of evaluating its initializer. The precise rules are given in sections 7.7 and 10.28.

The lazy semantics are given because we do not want a language where one tends to define expensive initialization computations, causing long application startup times. This is especially crucial for Dart, which is designed for coding client applications.


If a variable declaration does not explicitly specify a type, the type of the declared variable(s) is Dynamic, the unknown type.

A top-level variable is implicitly static. It is a compile-time error to preface a top level variable declaration with the built-in identifier static.  It is a compile-time error if a top level variable is initialized with an expression that is not a compile-time constant.


Static Variables


Static variables are variables whose declarations are immediately contained within a class declaration and that are declared static. The static variables of a class C are those static variables declared by C.

A static variable declaration of one of the forms static T v;, static T v = e; or static final T v = e; always induces an implicit static getter function with signature

static T get v()

whose invocation evaluates as described below.

A static variable declaration of one of the forms static var  v;, static var  v = e; or static final v = e; always induces an implicit static getter function with signature

static get v()

whose invocation evaluates as described below.

A non-final static variable declaration of the form static T v; or the form static T v = e; always induces an implicit static setter function with signature

static void set v(T x)

whose execution sets the value of v to the incoming argument x.

A non-final static variable declaration of the form static var v; or the form static var v = e; always induces an implicit static setter function with signature

static set v(x)

whose execution sets the value of v to the incoming argument x.

Evaluation of static variable getters



Let d be the declaration of a static variable v. The implicit getter method of v executes as follows:
  • If d is of one of the forms static var v = e; , static T v = e; , static final v = e; or static final T v = e; and no value has yet been stored into v then the initializer expression e is evaluated. If the evaluation succeeded yielding an object o, let r = o, otherwise let r = null. In any case, r is stored into v. The result of executing the getter is r. Otherwise
  • The result of executing the getter method is the value stored in v.  



Identifier Reference


An identifier expression consists of a single identifier; it provides access to an object via an unqualified name.

identifier:
      IDENTIFIER
  | BUILT_IN_IDENTIFIER
  ;


IDENTIFIER_NO_DOLLAR:
     IDENTIFIER_START_NO_DOLLAR IDENTIFIER_PART_NO_DOLLAR*
   ;
IDENTIFIER:
     IDENTIFIER_START IDENTIFIER_PART*
   ;
   ;

BUILT_IN_IDENTIFIER:      abstract
   | assert
   | call
   | Dynamic
   | factory
   | get
   | implements
   | import
   | interface
   | library
   | negate
   | operator
   | set
   | source
   | static
   | typedef
   ;


IDENTIFIER_START:      IDENTIFIER_START_NO_DOLLAR
   | '$'
   ;
IDENTIFIER_START_NO_DOLLAR:
     LETTER
   | '_'
   ;

IDENTIFIER_PART_NO_DOLLAR:      IDENTIFIER_START_NO_DOLLAR
   | DIGIT
   ;



IDENTIFIER_PART:      IDENTIFIER_START
   | DIGIT
   ;
qualified:
     identifier ('.' identifier)?
   ;



A built-in identifier is one of the identifiers produced by the production BUILT_IN_IDENTIFIER. It is a compile-time error if a built-in identifier is used as the declared name of a class, interface, type variable or type alias. It is a compile-time error to use a built-in identifier other than   Dynamic as a type annotation. It is a static warning if a built-in identifier is used as the name of a user-defined declaration, be it a variable, function, type or label, with the exception of user defined operators named negate or call.

Built-in identifiers are identifiers that are used as keywords in Dart, but are not reserved words in Javascript. To minimize incompatibilities when porting Javascript code to Dart, we do not make these into reserved words. However, a built-in identifier may not be used to name a class or type.  In other words, they are treated as reserved words when used as types. This eliminates many confusing situations without causing compatibility problems.

Evaluation of an identifier expression e of the form id proceeds as follows:
Let d be the innermost declaration in the enclosing lexical scope whose name is id. It is a compile-time error if d is a class, interface, type alias or type variable. If no such declaration exists in the lexical scope, let d be the declaration of the inherited member named id if it exists.
  • If d is a library variable then:
    • If d is of one of the forms var v = ei; , T var v = ei; , final v = ei; or final T v = ei; and no value has yet been stored into v then the initializer expression ei is evaluated. If the evaluation succeeded yielding an object o, let r = o, otherwise let r = null. In any case, r is stored into v. The value of e is r. Otherwise
    • e evaluates to the current binding of id.  This case also applies if d is a library function declaration, as these are equivalent to function-valued variable declarations.
  • If d is a local variable or formal parameter then e evaluates to the current binding of id.  This case also applies if d is a local function declaration, as these are equivalent to function-valued variable declarations.
  • If d is a static method, then e evaluates to the function defined by d.
  • If d is the declaration of a static variable or static getter declared in class C, then e is equivalent to the getter invocation C.id.
  • If d is the declaration of a top level getter, then e is equivalent to the getter invocation id.
  • Otherwise e is equivalent to the property extraction  this.id.

Monday, February 27, 2012

Upcoming changes to the isolate API

Posted by Sigmund Cherem

We are actively working on improving the isolate APIs. If you have code that uses isolates today, some of our upcoming changes will likely break your code. Here are a few of the changes coming up:
  • We are moving the isolates code out of corelib into a standalone 'dart:isolate' library.
  • We are making any top-level static function a valid entrypoint for an isolate, so you'll no longer have to create a class to define an isolate's entrypoint.
  • We want to simplify other parts of the API too, like how to obtain a port after spawning an isolate.
  • Later on, we plan to support spawning an isolate given a URL to its code.
For example, this code written with today's API:

// soon to be deprecated!
class MyIsolate extends Isolate {
  MyIsolate() : super.heavy();

  main() {
    port.receive((msg, reply) => reply.send("re: $msg"));
  }
}

main() {
  MyIsolate myIsolate = new MyIsolate();
  myIsolate.spawn().then((SendPort sendPort) {
    sendPort.call("hi").receive((msg, _) => print(msg));
  });
}


could be written as follows:

// coming soon!
#import('dart:isolate', prefix: 'isolate');

isolateCode() {
  isolate.port.receive((msg, reply) => reply.send("re: $msg"));
}

main() {
  SendPort sendPort = isolate.spawnFunction(isolateCode);
  sendPort.call("hi").then(print);
}


There are many details still under debate, so watch news.dartlang.org for updates when these and future changes land in trunk.

Saturday, February 25, 2012

New Dart Editor now bundles and launches Dartium

Posted by Eric Clayberg


A new Dart Editor build is available, download it now to get started.
 
Highlights for build 4577 include:
  • SDK and Dartium bundled with Editor
  • Editor launches apps in Dartium by default
  • Always use Frog to generate JavaScript
  • JavaScript generated only when launching non-Dartium browser
  • General fixes and performance improvements
  • Omnibox opens search view when return pressed
  • Add hyperlinking support to stacktraces that display in the console view
  • Enhanced welcome page 

For more information, please read the change log.

Check out the Dart Editor tutorial to get started.

Friday, February 24, 2012

Dart Team's Weekly Digest

Posted by Anders Sandholm

Quick update on what happened in Dart-land this week.
  • While we’ve seen the first steps taken in local inspection in the debugger in Dartium, the VM is implementing debugger stepping. The VM is also adding support for object groups to enable proper GC in Dartium and we’ve seen the first few code reviews, commits and build breaks by the new compiler infrastructure. Finally, the VM team has been fixing overly aggressive type checks which should only be static type warnings.
  • In the editor, we only generate JS when launching a Dart app in a non-Dartium browser, we introduced a switch to always use Frog for JS code generation and cleaned up the welcome page. Finally, a few omnibox search improvements were landed along with analysis performance improvements and general fixes.
  • Wrapper-less HTML generator was checked in and we had lots of infrastructure work - getting rid of instability in buildbots, testing frog hosted in browser (with frogpad).
  • In the dart:io library, performance of asynchronous directory and file operations improved using a native thread pool instead of isolates. The improvement is more than a factor of 80(!) on a loop that just creates and deletes files. Yay! Also, file APIs were extended with convenience methods for reading the whole contents of a file with one simple call (readAsBytes, readAsText, readAsLines).
    Example: new File(‘file.txt’).readAsText(‘UTF-8’);

Friday, February 17, 2012

Enabling type checks

Posted by Seth Ladd

Adding types to your Dart program helps express your intent more clearly to your fellow developers. The Dart platform can also use those type annotations to catch errors and warn you of problems from mismatches or bugs from incorrect types. Turning on "checked mode" will enable these type checks, catching your bugs early and providing valuable feedback during development.

The Dart VM can run in two modes: checked and production. Checked mode turns on type assertions, and reports on type mismatches and bugs. Production mode runs with the type assertions turned off, which may result in a speed boost.

We highly encourage you to run in checked mode during any and all development. In checked mode, you will see errors like "type 'OneByteString' is not assignable to type 'num' of 'a'" if there are type mismatches:

To enabled checked mode, use these methods:
  • for the VM: --enable_type_checks --enable_asserts
  • for Dartium:  DART_FLAGS='--enable_type_checks --enable_asserts' path/chrome
  • for frog: --enable_type_checks
You can download Dartium, and find the VM and fog in the SDK.

Jim Hugunin, an engineer on the Dart project, has this perspective:

I really like both static and dynamically typed languages.  Up until joining the Dart team, my preferred development experience was a mix of Python and C# - with a lot of work invested to make that pleasant on both ends.  I find dynamic typing much more productive for the early stages of development and I find static typing much more productive when working on more mature code with larger teams.

I much prefer Python over "looser" dynamic languages like JS, Perl or TCL because it is more agressive about providing runtime errors when I do something stupid.  Simple things like o.x throwing an exception when o has no member named 'x' or 2 + "2" throwing an exception rather than trying to guess if the result should be "22" or 4.  These runtime type errors do slightly reduce my flexibility, but the errors that they find early in my code are always worth the tradeoff.

What gets me most excited about Dart as a language is its mix of these two programming paradigms that lets me move between them as fluidly as possible.  However, if I don't enable runtime type checks, I often feel that Dart is more like TCL or Perl rather than my friendly Python.
In summary, please use checked mode when developing Dart code. Checked mode combined with type annotations will help you catch errors and bugs early, always a good thing.

Method Cascades in Dart

Posted by Gilad Bracha

(UPDATE: Method cascades are now implemented.)

The idea of a cascaded method invocation originates in Smalltalk, and has been proposed for Dart.  The motivation is to make it easier to write more fluent interfaces. 

Usually, fluent interfaces rely on method chaining. Say you want to add a large number of elements to a table:

myTokenTable.add("aToken");
myTokenTable.add("anotherToken");
// many lines elided here
// and here 
// and on and on
myTokenTable.add("theUmpteenthToken");

You might want to write this as

myTokenTable.add("aToken")
            .add("anotherToken").  
            // many lines elided here
            // and here 
            // and on and on
            .add("theUmpteenthToken");

but this requires that add() return the receiver, myTokenTable, instead of the element you just added. The API designer has to plan for this, and it may conflict with other use cases. With cascades, no one needs to plan ahead or make this sort of tradeoff.  The add() method can do its usual thing and return its arguments. However, you can get a chaining effect using cascades:

myTokenTable
  ..add("aToken");
  ..add("anotherToken");
// many lines elided here
// and here 
// and on and on
  ..add("theUmpteenthToken");


Here, ".." is the cascaded method invocation operation.  The ".." syntax invokes a method (or setter or getter) but discards the result, and returns the original receiver instead.

In brief, method cascades provide a syntactic sugar for situations where the receiver of a method invocation might otherwise have to be repeated. Instead of writing:


var address = getAddress();
address.setStreet(“Elm”, “13a”);
address.city = “Carthage”;
address.state = “Eurasia”
address.zip(66666, extended: 6666);

One may write

getAddress()
 ..setStreet(“Elm”, “13a”)
 ..city = “Carthage”
 ..state = “Eurasia”
 ..zip(66666, extended: 6666);


The sugar pays off the more complex the API, the longer the receiver of the cascaded method invocations, and the more methods are being directed toward that receiver. Cascades are expressions, so they also compose better than statements.  A cascade always evaluates to its initial receiver (the details are in the draft specification at the end of this document).

Below you'll find a number of examples, and a draft specification. As always, feedback is welcome. However, I'm about to go on vacation - so don't be offended if it takes a while before I respond to any of your comments.

Examples


The examples below show the use of the construct using a couple of indentation styles. All styles place cascaded access on a separate line, which improves readability.

Example 1


Consider using a (modified) String API:

String s = (new StringBuffer()
..add('Jenny ')
..add('I ')
..add('got ')
..add('your ')
..add('number')
).toString();


Example 2


Another common example would be using a builder API

final addressBook = (new AddressBookBuilder()
..name = 'jenny'
..email = 'jenny867@aol.com'
..phone = (new PhoneNumberBuilder()
  ..number = '867-5309'
  ..label = 'home'
 ).build()
).build();


Example 3



class Point {
num x;
num y;

Point() {
  x = 0;
  y = 0;
}
void scale(num factor) {
 x *= factor;
 y *= factor;
}

// Hack to display debugging output while within a cascade. Naturally you can't use
// the regular print statement.
void log(String msg) {
 print ('logged ($x, $y): $msg');
 }

}

void main(){

num x = 10;
num y = 42; // not used
var p = new Point();
p..log('start')
 ..x = x
 ..scale(10)
 ..log('scaled')
 ..x++
 ..y = x + p.x + p.y;
print('p.x = ${p.x}, p.y = ${p.y}. x = $x');
}



Output:


logged (0, 0): start
logged (100, 0): scaled
p.x = 101, p.y = 111, x = 10




Example 4


class Node {
String key;
Node(this.key);
Node left;
Node right;
}


void main() {
Node right = new Node('e');
Node root = new Node('root')
 ..left = (new Node('a')
   ..left = (new Node('b')
     ..left = new Node('c')
     )
     ..right = Node('d')
 )
 ..right = right;
print(root);
}



Example 5

The following example is perhaps more typical of what you might do in a web application.

var dq = document.query('#mypanel').queryAll('TABLE .firstCol');
dq.classes.remove('firstCol');
dq.style
  ..background = 'red'
  ..border = '2px solid black'
;
dq.nodes.add(new Element.html('<span>This cell is now red</span>')) // ?
;

It might be even nicer if cascades nested, but the nesting makes things hard to read. 


document.query('#mypanel').queryAll('TABLE .firstCol')
..classes.remove('firstCol');
..(style
   ..background = 'red'
   ..border = '2px solid black'
) ..nodes.add(new Element.html('<span>This cell is now red</span>')) // Not legal, just an idea for nesting

Maybe in the future we'll find a way to support such nesting in a truly readable way. For now we defer the issue and stick with one level of cascading.




Example 6



var dq = document.query('#myTable');
var qfc = dq.queryAll('.firstColumn');
qfc.style
   ..background = 'red'
   ..border = '2px solid black'
  ;
qfc.text = 'first column';

dq.queryAll('.lastColumn')
  ..style.background = 'blue'
  ..text = 'last column';


Example 7


view.node.style
..position = 'absolute'
..left = '${_measuredLeft}px'
..top = '${_measuredTop}px'
..width = '${_measuredWidth}px'
..height = '${_measuredHeight}px'
..zIndex = '${layoutParams.layer}'
;



Example 8


front
..beginPath()
..fillStyle = penColor
..arc(tx, ty, penWidth/2+2, 0, PI2, true)
..fill()
..moveTo(wx, wy)
..strokeStyle = "black"
..lineTo(tx, ty)
..closePath()
..stroke()
;




Example 9


document.queryAll('myDiv')
        ..classes.remove('off') // ?
        ..classes.add('on') // ?
;





Example 10

Array access works as well


element.attributes
      ..['foo'] = bar
      ..['baz'] = bla
;



Specification



Here is an initial take on the specification for this proposal. Places where the current spec changes are highlighted in yellow.

A cascaded method invocation has the form e..suffix

where suffix is a sequence of operator, method, getter or setter invocations.

A cascaded method invocation expression of the form e..suffix is equivalent to the expression (t){t.suffix; return t;}(e).


Grammar Changes



topLevelExpression:      assignableExpression assignmentOperator cascade
   | conditionalExpression ('..' cascadeSection)*
   ;


primary:      thisExpression    | super assignableSelector
   | functionExpression
   | literal
   | identifier
   | newExpression
   | constantObjectExpression
   |
'(' topLevelExpression ')'    ;


cascadeSection:     (assignableSelector arguments*)+ (assignmentOperator expression)?
   ;