Tuesday, April 30, 2013

New Dart Editor Build With Enhanced Refactoring Support





A new Dart Editor build is available at www.dartlang.org/editor. Eric Clayberg fills us in on the changes:

  • Semantic highlighting enabled for new analysis engine.
  • New “Convert Method to Getter” and “Convert Getter to Method” refactorings.
  • New “Create Class” and “Create part” quick fixes.
  • New “Import Library” quick fixes.
  • Multiple hover text improvements.
  • Fixed several debugger bugs related to not being able to hit breakpoints.
  • Additional warnings and errors enabled in new analysis engine.
  • Many general improvements and fixes to new analysis engine.
        Breaking Change List:
  • MirrorSystem.libraries uses Uri instead of library names.
  • LibraryMirror.url changed to LibraryMirror.uri.
  • Rename dart:typeddata to dart:typed_data.
As always,view the changelog for the full list of changes, and to get started with the Editor see our tutorial.

Monday, April 29, 2013

Notes from the April 22 Dart Language Design Meeting


Once again, the ever-helpful Bob Nystrom fills us in on the language design discussions taking place amongst Dart engineers. Here are his notes from the April 22 language meeting:

elvis operator / safe navigation operator

Lars is fine with the idea of adding some syntactic sugar like this if it helps real users. Kasper thinks we should wait until after 1.0 to look into it since we'll need analyzer support, editor support, tests, etc.

Lars is worried about a safe navigation operator because he thinks it would be strange if people started using it everywhere.

The current plan is to wait until after 1.0 and then discuss it again.

unique library names

Kasper has an idea to ensure that library names are unique when packages are published on pub. He wants to make it easy for users to give unique names, so the easy idea is to use the package name as a prefix.

I mentioned that validating this at publish is the least user-friendly time to do this. Something in the editor would be less painful. I asked what value the user gets in return for having to enter a unique name for each of their libraries.

Gilad says: "Composability."

Kasper says its useful for the same reason we have 'part of': it makes it easier to see how the library fits into the program hierarchy.

Lars says it helps users track down errors where they've imported the same library from multiple URLs. It also helps with reflection, since the reflective API takes a library name as a key, you need a unique name to get a single library back.

According to Gilad, though, that API changed recently to identify libraries by URL. But library names are better for error-reporting, etc.

Kasper will put together an email for the language team with his proposal.

recursive types

Johnni mentioned we have recursive types for some typedef stuff.

Gilad says that's probably true, but we have some restrictions on them so they are probably meaningful.

[There was some discussion on the team about this point afterwards, so this may not be a settled point.]

question mark operator

Gilad isn't sure why we can't get rid of it. Almost all uses of it are in dart:html and those folks say we can get rid of it.

Lars thinks it's a nice addition to the language, but if it's not used and adds complexity, we can take it out. He wonders what the migration process would look like.

I will discuss it with the dart:html folks and see what they think.

super in constructors

According to Gilad, the VM team says allowing the super() in any position costs some performance. The only location that makes sense is after initializers and before the body. He always thought it should be at the end.

Lars says the initializer syntax is just a comma-separated list, so it seems a little wierd to have a warning if super is not at the end. Is the perf problem just a deficiency in the current impl?

Gilad isn't sure. He'll talk to Ivan.

Kasper says he likes seeing super() at the beginning. He usually finds it harder to read at the end, especially if there's many initializers.


Cheers!

As always, view the changelog for the full list of changes, and to get started with the Editor, see our tutorial.

Wednesday, April 24, 2013

New Dart Editor Build with Run Last Launch Option




A new Dart Editor build is available at www.dartlang.org/editor. Eric Clayberg fills us in on the changes:
  • Run > Always Run Last Launch menu option when enabled will always run the last launch unless user chooses another launch explicitly. 
  • “Refactor” top-level menu
  • Support for inlining getters and setters.
  • “Rename...” proposal in Quick Assist (Cmd+1)
  • Use import prefix for return type in 'Extract Method' refactoring.
  • Several Quick fixes.
  • Several debugger fixes.
  • Additional warnings and errors enabled in new analysis engine.
  • Many general improvements and fixes to new analysis engine.
Breaking Change List:
  • Invocation use Symbol instead of String for names.
  • Invocation.invokeOn was moved to InstanceMirror.delegate in dart:mirrors.
As always,view the changelog for the full list of changes, and to get started with the Editor see our tutorial.

Friday, April 19, 2013

Pub's New Constraint Solver

TL;DR: Pub now has a new constraint solver that will pick versions of packages that work with your SDK. No more "doesn't work with your SDK" errors. This should appear in your life in the next SDK build.

Pub's job is to look at your dependencies and select the best versions for them. Given things like  shared dependencies, that's surprisingly hard. NP-complete, in fact.

So our initial version solver for pub was a very simple one. It would always terminate in a reliable amount of time, but that meant it could fail to find a solution to your package's constraints even when a solution existed.

One area where that's painfully obvious is SDK constraints. Because the Dart SDK itself is changing rapidly, any package likely only works with one or a couple of versions of the SDK. A while back, we added support so you could note which versions of the SDK your package supports.

Unfortunately, pub's solver was too simple to do take advantage of that. Instead, it would just pick the latest versions and then yell at you when the versions it picked didn't work with your SDK. This was better than silently picking incompatible versions, but not by much.

We just finished landing a new version solver into bleeding_edge. This solver does do backtracking (backjumping actually) and it can and will select versions of packages that work with your SDK even if that requires transitively downgrading other packages along the dependency chain. Awesome!

However, this also means that now there's a potentially exponential chunk of code right in the middle of pub that has had no real-world usage yet. Scary! Pub has pretty solid tests, and I've run the new solver against every version of every package on pub.dartlang.org without a problem, but nothing compares to the real world.

So, with luck, this means everything will just get more awesome and stable.

But, there is a chance that your package could have a dependency graph that falls through the solver's heuristics and tickles some pathological behavior. If you see pub being very slow or failing in an unexpected way, please do file a bug. When you do, please run:

$ pub --verbosity solver install

and include the log output. I expect we will have to tune some things once we get a better picture of how real usage affects it.

Wednesday, April 17, 2013

New Quick Videos on Dart's Classes, Exceptions, and More

More Dart Tips videos are available, covering topics such as classes, getters and setters, exceptions, and more.



Get caught up and watch the following episodes now:
If you have questions or comments about the videos, or Dart in general, please join our mailing list. As we say on Dart Tips, stay sharp!

Goodbye InvocationMirror, Hello Invocation and Symbol


TL;DR: We added a class Symbol to dart:core, renamed the class InvocationMirror to Invocation (keeping it in dart:core), and moved Invoke.invokeOn to InstanceMirror.delegate (moving this functionality from dart:core to dart:mirrors). Furthermore, Function.apply and InstanceMirror.invoke take a Map<Symbol,dynamic> to represent named arguments. Finally, dart:mirror uses Symbol instead of String to represent names.






Previously, InvocationMirror looked like this:

abstract class InvocationMirror {
 String get memberName;
 List get positionalArguments;
 Map<String, dynamic> get namedArguments;
 bool get isMethod;
 bool get isGetter;
 bool get isSetter;
 bool get isAccessor => isGetter || isSetter;
 invokeOn(Object receiver);
}

This creates problems when minifying, both when compiling to JavaScript and when minifying Dart code.  For example, a method call like foo(), may get renamed to a() when minifying.  If this call ends up being handled by noSuchMethod, the invocation mirror passed to that method will have memberName == ‘a’, not memberName == ‘foo’.

Another problem with InvocationMirror is that using invokeOn turns off type inference in dart2js.  Type inference is an important tool for dart2js to generate efficient and compact JavaScript code.  Function.apply has the same problem.  This means that InvocationMirror.invokeOn is not only problematic when using minification.  It is a problem in general when compiling to JavaScript.

Returning to the problem of preserving names when minifying, a possible solution is to include a mapping between minified names and original names.  The downside to this is that this map is relatively large.

We are proposing another solution: do not use strings for names, instead use a new class Symbol:

/// Opaque name used by mirrors and invocations.
/// Use [MirrorSystem.getName] to obtain the underlying name as a String.
class Symbol {
 const Symbol(String name);
}

abstract class InvocationMirror {
 Symbol get memberName;
 List get positionalArguments;
 Map<Symbol, dynamic> get namedArguments;
 bool get isMethod;
 bool get isGetter;
 bool get isSetter;
 bool get isAccessor => isGetter || isSetter;
 invokeOn(Object receiver);
}

In addition, we propose to use Symbol instead of String to represent names in the library “dart:mirror” and to represent named arguments passed to Function.apply and InstanceMirror.invoke.

The advantage is that an expression like const Symbol(‘foo’) can also be minified so one can write the following without having a mapping between all mangled and unmangled names:

class Foo {
 noSuchMethod(InvocationMirror invocation) {
   if (invocation.memberName == const Symbol(‘foo’)) {
     print(‘Respond to foo()’);
     return invocation.invokeOn(someOtherObject);
   } else {
     return super.noSuchMethod(invocation);
   }
 }
}

It is possible to write:

...
   if (invocation.memberName == new Symbol(name)) {
...

We propose to warn in situations like this to alert the user to the fact that we have to include a mapping because a non-const symbol is created. In fact, we propose to emit similar warnings when using Function.apply and InvocationMirror.invokeOn.  We will also provide a tool that can display the cost of using these features.

In addition, we should consider if InvocationMirror has the right name.  A class prefixed with mirror belongs in the library dart:mirrors, not in the library dart:core. So we propose to change the name to Invocation.  In addition, the method invokeOn is really a reflective operation that belongs in dart:mirrors.  So we propose to move Invocation.invokeOn (nee InvocationMirror.invokeOn) to InstanceMirror.delegate.

In in this situation, the class Foo above would look like:

import ‘dart:mirrors’;

class Foo {
 noSuchMethod(Invocation invocation) {
   if (invocation.name == const Symbol(‘foo’)) {
     print(‘Respond to foo()’);
     return reflect(someOtherObject).delegate(invocation);
   } else {
     return super.noSuchMethod(invocation);
   }
 }
}

One question that arise is if InstanceMirror.delegate is “worse” than InvocationMirror.invokeOn in terms of impact on size and performance of generated JavaScript code.  Our estimate is that both options have equal impact if we use symbols, but this is a question that must be examined as we implement mirrors in dart2js.  However, the motivation for moving the method is not performance.

Interestingly, there are cases when InstanceMirror.invoke can be almost as fast as a regular call.  However, these cases are probably not interesting and a regular call would be a better option.  Mirrors are only interesting when the involved expressions are just so dynamic that they are not possible to analyze ahead of time.

InstanceMirror.delegate is assumed to be easier to analyze than having to extract the arguments from an Invocation and using InstanceMirror.invoke.  We also assume that there is less runtime overhead to forward a call using delegate versus invoke.

Restrictions on Symbol


The name argument to the Symbol constructor must not start with ‘_’ (underscore) and match one of these grammar rules:

  • identifier (“.” identifier)* ‘=’?
  • (identifier “.”)* operator (where operator is a user-defined operator)
  • ‘’ (an empty string)

Symbols like const Symbol(“foo.bar.baz”) is used to represent library names.  Furthermore, DeclarationMirror in dart:mirrors has a getter named qualifiedName and the operator[] in class “MyClass” in library “my_lib” would have the qualified name const Symbol(“my_lib.MyClass.[]”). The Dart Programming Language Specification states that:

The name of a setter is  obtained by appending the  string `='  to the identifier given in its signature.

So a setter “x” in “MyClass” would have the qualified name const Symbol(“my_lib.MyClass.x=”) and simple name const Symbol(“x=”).

Language Support for Symbol Literals


It would be possible to add another literal type to the language to represent instances of Symbol.  However, one should only add language features for commonly used constructs, and it is not currently clear that having another kind of literal is warranted since we are not aware of compelling use-cases outside the mirror API.  So we are not proposing to add a new kind of literal at this time.

Map Literals


We further propose to change the type of an untyped map literal from Map<String, dynamic> to Map<dynamic, dynamic>.  Also, the map literal syntax should be changed to allow at least Symbol keys.

FAQ


Q: Why is it problematic to have a getter to access the unmangled name of a Symbol?
A: Getting the unmangled name from a Symbol means that you have to include it in the generated JavaScript or Dart code. If the compiler can statically determine that you're trying to get the mangled name, it can warn and tell you the cost. If it is an accessor with a general name, for example, "name" then every time the compiler sees an untyped expression "e.name", it has to assume that you might be getting the unmangled name of a Symbol and warn. The problem is that there are many false positives on the getter, but no false positives on a static method. No matter what accessor name you choose, developers will tend to use the same name in their own classes. So you'll always have false positives. There are downsides to both solutions.  Using a static method is the conservative approach, and it would be possible to add a getter later.

Q: Why doesn’t Symbol.toString() return the unmangled name?
A: That would mean that you always have to include the unmangled name in the minified output (Dart or JavaScript), which might not be desirable.  See also the previous question.

Q: Is new Symbol(“foo”) really problematic for the compiler to deal with?
A: No, but it easier to understand a simple rule like “symbols should be const”, rather than, “after constant folding, inlining, etc., the compiler will warn if it cannot determine that the argument to Symbol is a constant string literal.”

Q: Why is Function.apply similar to using strings for member names? It doesn't seem to imply the use of a symbol except for named arguments.
A: When you use Function.apply, the compiler often cannot tell which function is being called and with how many arguments, or what their types are. This means that it has to assume that all closures (including tear-offs) may get invoked with arbitrary arguments. This makes it hard to optimize forEach, etc. A similar situation arises when the compiler cannot tell which methods are invoked through reflection, but in this case it is much worse than Function.apply, since all instance methods as well as closures become targets. This effectively turns off type inference.

Q: Why is Symbol not a subclass of String?
A: From a modelling perspective, there are two strings associated with a symbol.  A mangled (or minified) name and the original name written in source code (aka unmangled).  So rather than having an is-a relationship with String, it seems that the relationship is has-some.
Furthermore, if Symbol is a subclass of String, the Editor will not complain when you pass a string to, for example, InstanceMirror.invoke.

Q: Why can’t a symbol start with “_”?
A: In Dart, names starting with “_” are private to the library in which they’re used.  So you’ll have to use a LibraryMirror to create a private name.  The exact API is to be determined.

(Photo courtesy of NASA Webb Telescope under cc license.)

Tuesday, April 16, 2013

List of Last Minute M4 Breaking Changes

The M4 release saw the Core, Async, and Collection libraries stabilize. Dan Grove has compiled a list of the last minute breaking changes:

  • The separator argument in Iterable.join defaults to “” (instead of `null`).
  • All DateTime constants are non-abbreviated. Also changed DAYS_IN_WEEK to DAYS_PER_WEEK.
  • Removed deprecated classes and methods
    • CollectionSink
    • Stream.pipeInto
    • Iterable/Stream . max/min
    • Collection (List, Set and Queue now extend Iterable directly)
    • Datetime.</<=/>/>=
    • IOSink.writeStream (renamed to IOSink.addStream)
    • IOSink.writeBytes (renamed to IOSink.add)
    • StreamSink (renamed to EventSink)
  • Iterable.reduce/Stream.reduce introduced that does not require an initial value.
  • List range functions were refactored:
    • List.getRange takes an endIndex argument and returns an Iterable.
    • List.setRange takes an endIndex and an iterable (plus an optional skipCount).
    • List.removeRange takes an endIndex.
    • List.insertRange got removed.
    • List.replaceRange was added.
    • List.fillRange was added.
    • List.setAll was added. (not strictly speaking a range function).
  • Stream.hasSubscribers -> Stream.hasListener
  • Removed async:EventSinkView.
  • Removed the AsyncError class.
  • Removed StreamController.broadcast.
  • dart:html has had most Web Worker related APIs removed while the correct API is worked out. The Worker class remains for spawning Javascript workers
  • Renamed InvocationMirror to Invocation
  • Function.apply uses Symbol for named argument
  • dart:mirror now uses Symbol instead of String to represent names

As always, view the changelog for the full list of changes, and to get started with the Editor, see our tutorial.