Coder Social home page Coder Social logo

language's Introduction

Dart language evolution

Build Status

This repository is a place for the Dart language team to work on language changes and features, and to solicit and accept feedback and requests.

Dart language team

As of January 2024, the Dart language team consists of:

Organization

We follow this process for planning and rolling out language changes.

Features currently being worked on are listed in the language funnel.

Contributing

Anyone can participate in the discussion about language changes by participating on the dart language mailing list, by replying to issues in this repository, and by uploading documents, tests or other resources.

When commenting on issues in this repository, keep in mind:

  • 👍 reactions are more useful than comments to show support.
  • Motivating examples help us understand why you want new features more than pointers to other languages which have them. We love hearing feedback about your experiences with other languages, but we also want to know why they are right for Dart in particular.

License & patents

See LICENSE and PATENTS.

language's People

Contributors

alexgoussev avatar bwilkerson avatar creativecreatorormaybenot avatar davidmorgan avatar dcharkes avatar dependabot[bot] avatar devoncarew avatar eernstg avatar franklinyow avatar gnprice avatar jakemac53 avatar jmewes avatar kallentu avatar kevmoo avatar kwalrath avatar leafpetersen avatar lrhn avatar mit-mit avatar mnordine avatar mraleph avatar munificent avatar natebosch avatar parlough avatar pq avatar scheglov avatar sgrekhov avatar sigurdm avatar srawlins avatar stereotype441 avatar yumatan avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

language's Issues

As specified, type inference infers no constraint for Null <: Future<T>

The local inference informal specification (dart-lang/sdk#29371) says:

  • P is a subtype match for FutureOr<Q> with respect to L under constraints
    C:
    • If P is a subtype match for Future<Q> with respect to L under
      constraints C.
    • Or P is not a subtype match for Future<Q> with respect to L under
      constraints C
      • And P is a subtype match for Q with respect to L under constraints
        C

The analyzer behavior is slightly different in the case where P is a subtype match for both Future<Q> and Q. (This happens, for instance, if P is Null). In that case, if the attempt to match P against Future<Q> generates zero constraints, but the attempt to match P against Q generates constraints, then the constraints from matching P against Q are propagated.

This has a user visible effect in the analyzer. Consider the code:

void test(Future<int> f) async {
  var t = f.then((int x) {});
  (await t).foo();
}

The analyzer attempts to infer the type argument for then by matching Null <: Future<T>. This causes the type constraint Null <: T to be generated, therefore t has type Future<Null>, and (await t).foo() produces an error. If I change the analyzer to follow the informal specification, it infers a type of Future<dynamic> for t, and no error is issued. Issuing an error seems like a better behavior here.

(Note that the common front end's behavior is different still: it infers a type of dynamic for t, due to dart-lang/sdk#33044.)

@leafpetersen @jmesserly what do you think?

FutureOr conditional expression typing issue

I'm running into a typing issue similar to dart-lang/sdk#28783, but in the context of a conditional expression (?:)

  FutureOr<bool> routerCanDeactivate(next, prev) =>
      someExpression
          ? true
          : methodReturningFutureBool();

Under 1.22.1, this results in an analyzer warning:

WARNING: Unsafe implicit cast from 'Object' to 'FutureOr'. This usually indicates that type information was lost and resulted in 'dynamic' and/or a place that will have a failure at runtime.

But the analyzer is happy if I put an explicit cast (which IMHO should be unnecessary):

  FutureOr<bool> routerCanDeactivate(next, prev) =>
      someExpression
          ? true as FutureOr<bool> // <================== cast
          : methodReturningFutureBool();

@leafpetersen @bwilkerson @nex - I wasn't sure if you'd want a separate issue for this, or whether you'd prefer clumping it up with dart-lang/sdk#28783. It felt like ?: might have its typing rules handled separately from if-then-else statements. Anyhow, I'll let you mark this as a dup if you want to merge the issues.

cc @kwalrath @matanlurey

Returning a function expression from an async function causes type inference problems.

In the following code:

typedef int IntToInt(int i);
Future<IntToInt> b() async {
  return (x) => x;
}

I would expect the type of x to be inferred as int. However, it is not. It is inferred as type dynamic.

Similar constructions using synchronous code or generators work fine, e.g.:

IntToInt a() {
  return (x) => x; // x has type int
}
Iterable<IntToInt> c() sync* {
  yield (x) => x; // x has type int
}
Stream<IntToInt> d() async* {
  yield (x) => x; // x has type int
}

The problem is occurring because the context of the return expression is (correctly) inferred to be FutureOr<IntToInt>. However, when we try to infer the type of (x) => x in this context, we see that FutureOr<IntToInt> is not a function type, so we (erroneously) ignore it.

This bug currently exists only in analyzer, however I expect it will soon be replicated in front_end, so I'm filing it against both.

Inference should flow information between arguments in a generic function call

EDIT by @jmesserly

Inference should flow information up/down between arguments in a generic function call. This will help inference common methods like Iterable.fold and Future.forEach.


(original description)
We currently do downwards and upwards inference independently. This gets us a fair bit, but we should eventually integrate the two, probably following the colored local type inference approach.

Algebraic Data Types (ADTs, Sealed Classes, Enum with associated values)

ADTs are a very important part of any modern programming language.

Imagine you have a network call that submits login credentials. This call can:

  • log the user in
  • fail because the user entered incorrect wrong credentials
  • fail because the user doesn't have network connectivity
  • fail because of an unknown defect in your code or server broke API contract and the call failed

In Kotlin, the return value could be represented as the following sealed class

sealed class LoginResponse {
    data class Success(val authToken) : LoginResponse()
    object InvalidCredentials : LoginResponse()
    object NoNetwork : LoginResponse()
    data class UnexpectedException(val exception: Exception) : LoginResponse()
}

Kotlin's when statement unwraps this beautifully, smart casting LoginResponse.

fun on(loginResponse: LoginResponse) {
    return when (loginResponse) {
        is LoginResponse.Success -> {
            // direct access to auth token available w/o need to cast
            loginResponse.authToken
        }
        is LoginResponse.InvalidCredentials -> {

        }
        is LoginResponse.NoNetwork -> {

        }
        is LoginResponse.Unexpected -> {
            // direct access to exception available w/o need to cast
            loginResponse.exception
        }
    }
}

Sadly, languages like Java and Dart are unable to elegantly express this concept (ADTs). For a best case example, checkout out Retrofit's Response object. It is a single pojo that contains both:

Both these fields are nullable, but one must be non-null and the other must be null. To know which field can be accessed, you have to check the .isSuccessful() flag.

Now imagine the verbosity if this best case scenario has to scale to 4 or more possible results. A whole new enum class would have to be added to work around it...it's not pretty.

Please add support for ADTs to Dart.

note: As an Android developer, I find that Flutter is an interesting proposition that is currently held back by the language.

Assignment semantics needs clarification.

In the language specification, Sect. \ref{assignment} a rather large number of cases are described, specifying the semantics of assignment.

These cases match up with the syntax for "normal" assignments (assignableExpression assignmentOperator expression), but it does not seem to cover the assignments that arise in cascadeSection. For instance, it seems that the spec is silent on whether e..foo() = 42 is an error, and how/when. It is obviously not a syntax error (with the current grammar).

For a discussion where this kind of issue has come up, please check dart-lang/sdk#28367.

It may be useful to abstract over the assignment operation and say once and for all what it means to assign a value to "something" (for a local variable it's about raw bindings, for almost everything else it's about calling a setter), and then we could specify how to evaluate an expression to such a "something". It's not going to be as simple as a C 'lvalue', but we would at least have a concept which could be used to divide the assignment into phases: (1) find the thing which is the 'target' of the assignment, (2) find the value to assign, (3) perform the assignment. Currently we do not have a separate concept for 'target'.

Specification special-cases static type of ~/, not .remainder.

The specification has special-cased the static type analysis of the int operators +, -, *, % and ~/ to be int if the argument is int, and double if the argument is double.

This is incorrect for ~/, which is declared as returning int in all cases (so specifying "4 ~/ 0.5" to be double is wrong), and it misses the remainder function, which should be treated just as special as the % operator.

Support shorthand class creation syntax

For classes with a single constructor that takes in a few values.

class User {
  final String firstName;
  final String lastName;

  User({@required this.firstName, @required this.lastName});
}

It would be much cleaner and concise to simply allow a "primary constructor":

class User({@required this.firstName, @required this.lastName}) {
  final String firstName;
  final String lastName;
}

Duplicating constructor and class declaration seems a little clunky. When we have more fields,
this duplication is further known and wish we could take it a step further to allow:

class User({@required final String firstName, @required final String lastName});

Less duplication in code will lead to nice details in our widgets for flutter like from this:

class AppDetails extends StatefulWidget {
  final String url;
  final String jobName;

  AppDetails({@required this.url, @required this.jobName});

  @override
  AppDetailsState createState()  => new AppDetailsState(this.url, initialJobName: jobName);
}

class AppDetailsState extends State<AppDetails> {
  String selectedJobName;
  final String jobUrl;

  AppDetailsState(this.jobUrl, {@required String initialJobName}) {
    this.selectedJobName = initialJobName;
  }

  // state implementation below

}

to this:

class AppDetails({@required final String url, @required final String jobName})
 extends StatefulWidget {
  @override
  AppDetailsState createState() => new AppDetailsState(this.url, initialJobName: jobName);
}

class AppDetailsState(final String jobUrl, {@required String initialJobName}) 
 extends State<AppDetails> {

  // state implementation below

from 17 lines of boilerplate to 8.

Minor omission in metadata section of spec

Section 15 (Metadata) currently reads:

Metadata can appear before a library, part header, class, typedef, type parameter,
constructor, factory, function, field, parameter, or variable declaration
and before an import, export or part directive.

but this list is incomplete. It should include 'enum' in the list of declarations.

Add first class support for method forwarding

It's a common pattern to wrap an interface with a Delegating class which forwards all methods to a instance of the same interface and allows selectively overriding methods.

For example see Delegating* classes in package:collection and package:async

It would be cool if this was automatic rather than needing to manually write these classes.

Here's a straw man proposal:

abstract class SomeInterface {
  String someMethod();
  int someOtherMethod();
}

class Foo implements SomeInterface {
  final delegate SomeInterface _delegate;
  Foo(this._delegate);

  @override
  String someMethod() => 'Foo implementation';

  // Implicitly:
  // int someOtherMethod() => _delegate.someOtherMethod();
}

If:

  • a field is marked delegate
  • The delegate field is statically determined to be of type Foo
  • The class implements Foo

Then:

  • Any methods in Foo which are not directly implemented in the class are automatically implemented by forwarding to the field marked delegate.

I think this also could work with multiple delegates and it would be a static error to have a method with identical signatures in two interfaces with ambiguous forwarding. This is similar to a static error when implementing two interfaces with the same method and conflicting signatures.

class Foo implements First, Second {
  final delegate First _first;
  final delegate Second _second;
  Foo(this._first, this._second);
}

Support generic arguments for (named) constructors

Sometimes constructors need to have generics that don't appear in the class itself in order to fully express their type relationships. new Map.fromIterable() is a good example:

Map.fromIterable(Iterable elements, {K key(element), V value(element)});

If elements has a generic type, the key() and value() callbacks are guaranteed to be passed an argument of that type, but there's currently no way to express that. Using generic types here blocks inference and makes it very difficult to use this API in strong mode. I propose that we be able to declare:

Map.fromIterable<E>(Iterable<E> elements, {K key(E element), V value(E element)});

which would be called like new Map<String, String>.fromIterable<int>(...). This syntax allows the user to omit the generic argument to the constructor while retaining it for the class itself if desired.

For loop is under-specified. Doesn't address "for(type x...", "for(final x...", "for(expr..." or "for(const x ...".

The specification of a for loop only handles the case
  for (var v = ...;...;...) ...
but the syntax allows final, const and typed variables as well, as well as a non-declaration (plain expression or nothing) in the first part.

The implementations handle the non-declaration in similar ways: there is no loop variable, and the expressions just have to work on existing variables. That means that the algorithm in the spec cannot be used (it refers to a variable that doesn't exist).

Neither implementation handles 'final' gracefully:
  for(final i = 0; i < 10; i++) { print(i); }
will throw a "no setter for i" in the increment operation.
If following the "for(var..." specification, that may or may not be correct, since the fresh variable from step 4 isn't specified to have any type or finality. It should have the same type as the original variable (or you won't get type errors if assigning wrong values after the first iteration).

It would be preferable if the specification allowed 'final' in such a way that the variable is final except in the increment part of the for. I believe it was once defined that way.

A const declaration should probably just be disallowed. Neither implementation allows it.

Specify toplevel inference

From discussion in another bug, here is a sketch of how top level inference should work. We need to turn this into an informal, and then formal, specification.

  • Mark every top level, static or instance declaration(fields, setters, getters, constructors, methods) with an explicit type as available.
  • For each declaration D which is not available
    • If D is a method, setter, or getter declaration with name x:
      • Mark x as unavailable
      • Perform override inference for x
      • Record the inferred type for x and mark x as available
    • If D is a constructor declaration C(...) for which one or more of the parameters is declared as an initializing formal without an explicit type:
      • Mark C as unavailable
      • Perform top level inference on each of the fields used as an initializing formal for C (without an explicit type)
      • Record the inferred type of C, and mark it as available
    • If D is a declaration of an instance field declaration declaring the name x, which overrides another field, setter, or getter:
      • Mark x as unavailable
      • Perform override inference on x
      • Record the type of x and mark x as available
    • If D is a declaration of a top level variable or static field declaration or a non-overriding instance field declaration, declaring the name x, and which is initialized with e:
      • Mark x as unavailable
      • Perform local type inference on e, with the following modifications:
        • If local type inference requires looking up the type of a name y whose type has not yet been inferred and y is not unavailable then recursively perform inference on y before continuing.
        • If local type inference requires looking up the type of a name y whose type has not yet been inferred and y is unavailable, it is an error and inference fails
      • Record the inferred type of x and mark it available

Add a "try-with-resources" or "using" style syntax for automatic resource management

One neat feature in Java and C# that I think would be great for Dart is the ability to have a resource be automatically closeable/disposable. This is accomplished in Java with the Closeable and/or AutoCloseable interface paired with the following try-catch syntax:

try (CloseableResource cr = new CloseableResource) {
  ...
} //optionally add a catch and/or finally branch here

and in C# with the IDisposable and using syntax:

using (IDisposableResource idr = new IDisposableResource()) {
  ...
}

This helps catch resource leaks because the compiler can detect and warn the developer when close/dispose has not been called or has been called unsafely. I'd love to see this feature in Dart!

Edits: Spelling and grammar fixes

Mixin composition

This issue was originally filed by @simonpai


Currently Dart does not support direct mixin composition as mentioned in the document (http://www.dartlang.org/articles/mixins/). However if we have a way to either define M1 * M2 or just make

class X extends Object with A, B {
   ...
}
typedef Y = Object with A, B;

X, Y valid mixin candidates, it will come in very handy to build flexible class plugins.

Algebraically there is no loophole to define the composition operator, and the association will work perfectly.

Related issue:
http://www.dartbug.com/8127

Constant constructor call should be legal in another constant constructor definition.

This issue was originally filed by @Cat-sushi


The code below is illegal with the current language specification.

  class C {
    final x;
    const C(this.x);
  }

  class D {
    final C c;
    const D(x) : this.c = const C(x); // compile-time error!
  }

I understand that 'x' in 'const C(x);' is not a compile-time constant, but a potentially constant expression, and this is the reason why the constructor call 'call C(x);' is illegal.
I also understand the reason why the 'x' is potentially constant, the constantivity of 'x' is depends on the call site which calls the constructor whether with 'const' or with 'new'.

On the other hand, with my understanding, the compiler evaluates the result of constant expressions at compile-time, and the compiler can check constantivity at compile-time with call site sequence.
At the same time, in run-time context, constructors are less constrained, and the language processor can simply regard 'const' of 'const C(x);' as 'new', and can call the prepared run-time constructor.
I think the disregard of keyword 'const' and the need for the run-time constructor of the constructor call 'const C(x);' in run-time context are kind of similar to those of constant constructor definition like 'const C(this.x);' or const 'D(x)...;'.

So, regardless of discussion in issue dart-lang/sdk#392 and issue dart-lang/sdk#19558, I think constant constructor calls in another constant constructor definition should be legal.
And, I feel it is more natural.

In addition, I think this proposal is upper compatible of the current language specification.

Add syntax for character code constants.

The currently simplest way to get the character code of the character '9' is either "9".charCodeAt(0), which isn't even constant, or writing the number constant, e.g., 0x39. Or define a whole slew of constants as in the dart2js characters.dart library:<http://code.google.com/p/dart/source/browse/branches/bleeding_edge/dart/lib/compiler/implementation/util/characters.dart>

It would improve readability and usability a lot if there was a simple way to specify "the character code of the character _", like C and Java's '9', Ruby's ?9, Scheme's #\9 or SML's #"9".

I propose the SML syntax since it doesn't collide with any other Dart syntax, and it could allow arbitrary Dart single-character string literals, piggy-backing on known string syntax, so it's possible to write, e.g., #"\n" instead of 0x10.
It should only work as a literal, no #stringVar or multi-character strings, or other funky stuff.

I don't want a character type, just a way to create integer constants that is both readable, simple and compile-time constant.

Feature request: support for nested classes.

This issue was originally filed by [email protected]


It would be nice if we can introduce classes local to a given enclosing class.

class Outer {
  void doSomething() {
    var inner = new Inner();
  }
  class _Inner {
       
  }
}

This allows define class that is invisible outside of the Outer class scope.

I understand that this feature requires more investigation. As for me it has a limited power if a class is not the first class object (or a class could be a class member like fields or methods).

Add binary integer literals

This issue was originally filed by [email protected]


When working with bits and bytes, having binary integer literals comes handy, as a lot of languages acknowledged (Python, Ruby, Java, even GCC has them as an extension). I believe that the reasoning behind adding binary literals to Java 7, as per http://mail.openjdk.java.net/pipermail/coin-dev/2009-March/000929.html, is equally valid to Dart, and therefore I propose to add binary literals in the same form ("0b100000" as an equivalent of "0x20"). I think that implementation is no concern (I did it in the VM and it was pretty straightforward, as I describe in http://ladicek.github.com/2012/04/29/hacking-the-vm-adding-binary-integer-literals.html).

Allow both optional positional and optional named arguments in the same function signature.

Dart functions currently can have only either optional named parameters or optional positional parameters, but not both.

While developing libraries repeatedly run into cases where this restriction gets in the way of the signature we want.
It would be preferable if you could have both kinds of parameters on the same function.
The only syntax change necessary is to the declaration of functions. The call syntax is unaffected, and so is noSuchMethod/Function.apply.

Small bug in the definition of "instance {methods, getters, setters} of a class"

@gbracha Section 10.9.1 Inheritance (3rd edition) defines inheritance of instance members in terms of accessible members of "a superclass" (i.e., the superclass or one of its superclasses) that are not overridden.

The language in Sections 10.1 Instance Methods, 10.2 Getters, and 10.3 Setters use the wording "its superclass", which is probably just left over from an earlier version. For example from 10.1:

The instance methods of a class C are those instance methods declared by C and the instance methods inherited by C from its superclass.

This would seem to disallow instance methods from superclasses of its superclass because elsewhere in the spec the words "its superclass" is always used to refer to "the superclass" of a class.

One fix is to change "inherited by C from its superclass." to "inherited by C from its superclasses." or similar. Another better fix might be to change to "inherited by C." and cross-reference Section 10.9.1 since that's where inheritance is defined.

Implementation issue for unsigned/triple-shift >>> operator

This is the implementation issue for the triple-shift >>> operator (unsigned shift), see language feature #120

The operator has the same precedence as >>.
The expression e1 >>> e2 is a compile-time constant expression if both e1 and e2 are compile-time constant expressions evaluating to integers (and int will implement the operator).
The symbol #>>> is valid (along with const Symbol(">>>")), as is x >>>= e as an expression.

Adding the new operator is non-breaking.

Specification should clearly specify how a mixin application defines a new class from a super-class and a mixin-class

This is a result of discussion in dart-lang/sdk#25764
First, specification should clearly define what is mixin. The current spec (4-th Edition, December 2015) contains only

A mixin describes the difference between a class and its superclass. A mixin
is always derived from an existing class declaration.

Specification should more clearly define "mixin". If "mixin" term is used in the specification it should be clearly defined. See dart-lang/sdk#25764

Second,

It is a compile-time error if a declared or derived mixin explicitly declares a constructor.

Again, no definition of "declared mixin" and "derived mixin"

Third, "C declares the same instance members as M" should be more clear if it emphasizes that only the declared members, not the inherited members, of M are declared by C.

Fourthly, please see dart-lang/sdk#25765. Spec should clearly state that it is an error if any of the cases below are illegal

class A {}
class S extends A {}
class M extends A {}

class C1 extends S with S {}
class C2 extends S with A {}
class C3 extends S with M, M, M {}

Add an expression-local declaration (let-expression).

There is no way to locally declare a variable in an expression.
In statements, a single statement can be replaced by a block statement that contains local variable declarations, but there is no way to do the same thing in an expression.

Example code (using "let/in" as syntax):

let var tmp = new Something() in new Other(tmp, tmp)

This can be useful in initializer lists where you can need to create a new object and use it in more than one place.

The current alternative, as used by the specification to explain desugaring of some constructs, uses a function literal to bind the new variable, like ((tmp) => new Other (tmp, tmp))(new Something()).
This has the disadvantage of not working well with async operations (if new Other(..) was more complex and contained an await, it would not be a correct rewrite).

The new syntax could be used by the specification to define desugarings, and can be used to make some expressions more readable by reducing the scope of temporary variables.

Alternatively, now that we have definite assignment analysis, we could allow var x = e as an expression.
It would effectively introduce x into the current scope, but the variable cannot be accessed until after the declaration point, even if that is in the middle of an expression. It'll b definitely unassigned before and definitely assigned after, which is something we can already handle.

Then the above example becomes Other(var tmp = Something(), tmp).
It will probably have to use the var or final marker, using a type can potentially be hard to parse: f(x + int y = 2, 2).
The precedence of a declaration would be very low, so the only place it won't need to be parenthesized is if it's at the end of an expression, or it's a collection element or parameter list entry (comma delimited).

update spec on evaluation order of deferred checks

I couldn't find in the spec a lot of details explaining deferred checks. The program below:

import 'a.dart' deferred as a;

main() {
  var x = 1;
  try {
    a.foo(x = 2);
  } finally {
    print(x);
}

We will be injecting a check that "a" is loaded before we allow the call to "foo". This check can be injected before or after arguments are evaluated to a value. This is implemented differently in dart2js and the VM: the example above prints 1 in dart2js and 2 in the vm.

In Dart 1 I'd have said we should implement the VM semantics. However, In Dart2 I believe we want the dart2js semantics instead: this matches the left-to-right consistency rule that we are adopting for Dart 2. I'm about to implement that in the FE at this moment.

@leafpetersen @lrhn @floitschG - can you clarify? would it be possible to explicitly call this out in the spec?

Related issue dart-lang/sdk#27577

Add data classes

Immutable data are used heavily for web applications today, commonly with Elm-like (redux, ngrx, ...) architectures. Most common thing web developer is doing with data is creating a copy of it with some fields changed, usually propagated to the root of state tree. JavaScript has spread operator for this. There should be a easy way to use immutable data structures in Dart. I would like to have data classes (inspired by Kotlin) in Dart. Possible API:

data class User {
  String name;
  int age;
}

Compiler assumes that all fields of data class are immutable. Compiler adds equals implementation based on shallow equals, hashCode implementation based on mix of all object fields, toString implementation of the form <Type> <fieldN>=<valueN>, and copy function to recreate object with some fields changed.

You may argue that there is already Built value package that allows to do similar things, but we have many issues with package, mainly:

  1. It requires writing a lot of boilerplate code
  2. It requires running watcher/manual code generation during development.
  3. It requires saving generated files to repository because code generation time is too large for big applications.

I have found that using built value actually decreases my productivity and I do my work faster with even manually writing builders for classes.

If data classes would be implemented on language level, it would increase developer productivity and optimizations can be made when compiling code to particular platform.

Feature Request: Variable Number of Arguments

This issue was originally filed by [email protected]


It would be nice to have variable numbers of arguments, a la python splats.

This would make porting python code to dart much cleaner.

For example, I would like to do something like this:

void myFunc(arg1, arg2, *anyRemainingArgs){
  var extraArg1 = anyRemainingArgs[0];
  var extraArg2 = anyRemainingArgs[1];
  ...
}

Specification: lack in definition of mixin application

Dart language specification (3-rd Edition, June 2015) reads (12.1 Mixin Application):

"A mixin application of the form S with M; defines a class C with superclass S.
A mixin application of the form S with M1, . . . ,Mk; defines a class C whose
superclass is the application of the mixin composition (12.2) Mk−1 � . . . �M1 to
S."

To the second case condition "where k > 1" should be added.

Nested typedefs

Currently typedef can only appear at the toplevel. If I have a class that I want to allow a user supplied callback and maintain type checking, there currently is no way:

class Foo<T> {
  Function _callback;
  Foo(void callback(T something)) : this._callback = callback;

  doSomething() {
    ... something ...
    _callback(result);
  }
}

Allow named function arguments anywhere in the argument list

Since named arguments are distinguishable from positional ones, allowing named arguments to be placed anywhere in the argument list can be done without changing calling semantics.

It is an advantage in some cases where you want to put a function argument last. Example:

expectAsync(() {
  ...
}, count: 2);

would be more readable as:

expectAsync(count: 2, () {
  ...
});

Function.apply unspecified

The static function Function.apply is mentioned here and here in the language specification, but Function.apply itself is never specified. We might want to specify it in a manner which is similar to the one given on the documentation page for Function.apply, such that the language specification is self-contained in this respect.

(Note that Function.apply needs to accept type arguments for the invocation as well as value arguments, and the documentation mentioned above is too old to include that).

Specification: need to elaborate postfix expression definition

Dart Language specification, 4-th Edition (December, 2015) "16.31 Postfix Expressions":

A postfix expression is either a primary expression, a function, method or getter invocation, or an invocation of a postfix operator on an expression e.
...
Execution of a postfix expression of the form C.v ++ is equivalent to executing
()fvar r = C.v; C.v = r + 1; return rg().
The static type of such an expression is the static type of C.v.
Execution of a postfix expression of the form e1.v++ is equivalent to executing
(x)fvar r = x.v; x.v = r + 1; return rg(e1).
The static type of such an expression is the static type of e1.v.
No any mention about the difference between C and e1. Clarification should be added that C is a type literal and e1 is an expression.

The same is true for C.v-- and e1.v-- defined in the same chapter of the spec

Consider changing the language to reduce problems with "break" at the end of switch cases.

(Split off from dart-lang/sdk#26673).

Some users have complained that "break" is required at the end of a switch case, wishing for this to be the default behavior (rather than the current behavior, which is to generate a runtime error unless the switch case in question is the last case in the switch).

Other users have complained that "break" is required at the end of a switch case where the analyzer can prove that the "break" is unreachable.

Also, it appears that analyzer doesn't actually require a "break" at the end of the last case in a switch; however, a strict reading of the language spec seems to say that it should. "Fixing" the analyzer to follow the spec in this case would likely create a lot of nuisance warnings, forcing users to introduce a lot of do-nothing "break" statements.

It seems like this area of the spec might be worth revisiting.

Union types

Currently Dart does not support function overloads based on parameter type and this makes it verbose/awkward to clone/wrap Javascript APIs which accept multiple types.

For example, WebSocket.send() can accept a String, a Blob or an ArrayBuffer.

In Dart, this can either be exposed as:
WebSocket.sendString, sendBlob, sendArrayBuffer which is verbose
or:
WebSocket.send(Dynamic data), which is no longer a self-documenting API.

It would be great to have some variant of union types, along the lines of JSDoc:
WebSocket.send(String|Blob|ArrayBuffer data);

Add `name` instance property to enum values

This issue was originally filed by @seaneagan


With the current spec it's difficult to get the name of an enum value, since the toString() result is prefixed with EnumClass.:

enumName(enumValue) {
  var s = enumValue.toString();
  return s.substring(s.indexOf('.') + 1);
}

It would be nice to just be able to do:

enumValue.name

Constant function literals

Static functions are compile time constants, but function literals are not.
It would be great if it was possible to write compile time constant function literals. They would necessarily have static scope (no access to "this") even if written inside a class declaration.

Constant function literals would create only one function object per function expression (no unification of different function expressions, even if they happen to have the same body).

This is particularly useful for default function parameters.

I suggest const <functionLiteral> as syntax. That would allow you to write, e.g.,:

class Map<K,V> {
  V getIfPresent(K key, [V onNotPresent() = const () => null]);
}

The current alternative is to declare the function as static:

class Map<K,V> {
  V getIfPresent(K key, [V onNotPresent() = _returnNull]);
  static _returnNull() => null;
}

You can use it to ensure that you don't create too many closures if you want to create a function inside a loop:

for (var x in xs) {
  x.somethingOrError(const (x) => throw new Failure(x));
}

which would otherwise create a new closure per iteration of the loop. The alternative is again to define a static function somewhere and use that, but it moves the logic away from where it's most readable.

The syntax shouldn't collide with any current use of "const", since we currently don't allow that syntax in expression position. It does collide with a constant constructor declaration, but the uses are different enough that I don't think it's a problem. If we want parity, we could allow const foo() => xx as a top-level declaration too, meaning the same as static, but that would make static redundant.

Bugs in the spec for for loops

The spec for for loops describes a statement of the form for (var v = e0; c; e) s. There are some missing cases:

  1. Multiple variables can be declared, but the spec only mentions one. The reader might infer either that multiple variables are treated uniformly, or else that the first one is special.
  2. There can be an expression instead of a variable declaration for the initializer. Presumably this is just evaluated and all the fresh variable/substitution stuff can be ignored.
  3. The initializer can be empty. There is otherwise no "empty expression" in Dart so the reader might wonder what happens in that case.
  4. The update is a possibly-empty sequence of expressions, and the spec does not otherwise define evaluation of a sequence of expressions. The definition of for loops just says 'the expression [v''/v]e is evaluated'. We need to say at least that this is left to right.

Also problematic is: "First the variable declaration statement var v = e0 is executed." There is no mention that this is in its own scope, and so by the normal scoping rules it would introduce a variable v to the block containing the for loop, initialized at the for loop, and thus accessible after the loop. This does not seem to be the intent.

Add possibility to consistently get object property name

We need to get object property name in cases like Angular 2 ngOnChanges (when you need to compare key from changes map with object property name):

ngOnChanges(Map<String, SimpleChange> changes);
It would be great to have something like nameof in C#, so that we could get property name and don't be afraid that someone will rename property.

nameof(obj.propertyName); // 'propertyName'

Population of scopes is not consistent

The language specification specifies that top level scopes are populated with entities in the following manner (Sect. Imports):

The {\em public namespace} of library $L$ is the mapping that maps the simple name 
of each public top-level member $m$ of $L$ to $m$.
The scope of a library $L$ consists of the names introduced by all top-level declarations
declared in $L$, and the names added by $L$'s imports (\ref{imports}).

This means that the top level scope of $L$ will bind the name of each class declared in $L$ to that class. So we can look up a class as such in the current library. This is confirmed by the following (Sect. Mixin Application):

The effect of a class definition of the form \code{\CLASS{} $C$ = $M$; } or the form
\code{\CLASS{} $C<T_1, \ldots, T_n>$ = $M$; } in library $L$  is to introduce the name
$C$ into the scope of $L$, bound to the class (\ref{classes}) defined by the mixin
application $M$.

I couldn't find a similar statement about regular class declarations, but you could claim that both mixin applications and regular class definitions are covered by the general rule about library scopes above.

The library namespace is used to define how imports work, and this means that we can look up classes as such from libraries that are imported 'immediately' (without a prefix).

However, when we import with a prefix we obtain a getter which returns the Type (Sect. Imports, talking about the members of prefix objects):

For every type $T$ named $id$ in $NS_n$, a corresponding getter named $id$ with return
type \code{Type}, that, when invoked, returns the type object for $T$.

So we sometimes have the getter which is used dynamically for obtaining a Type, and in that situation we don't have a suitable notion of what's in scope for the static analysis (where we'd want to look up the class as such), and we sometimes have the classes as such, and then we don't have a suitable getter which is needed at runtime (foo() => C;).

We can't just add both entries and use the resulting scopes both for static analysis and at runtime, because that would cause a name clash for every type name.

So we probably need to distinguish between static and dynamic scopes.

Members are defined in bits and pieces:

% Sect. Libraries and Scripts
The members of a library $L$ are those top level declarations given within $L$.

% Sect. Classes
The instance members of a class are its instance methods, getters, setters and
instance variables. The static members of a class are its static methods, getters,
setters and static variables. The members of a class are its static and instance members.

So in both cases members are declarations, including variables.

But we also have this:

% Sect. Variables
A library variable introduces a getter into the top level scope of the enclosing library.
A static class variable introduces a static getter into the immediately enclosing class.
An instance variable introduces an instance getter into the immediately enclosing class.
A mutable library variable introduces a setter into the top level scope of the enclosing library.
A mutable static class variable introduces a static setter into the immediately enclosing class. 
A mutable instance variable introduces an instance setter into the immediately enclosing class.

So a library scope may contain both a variable x and a getter x induced by the variable, which creates a name clash for every single variable.

For that, I guess we can just insist that variables are not added to any scopes, only the induced setters and getters are. This should work dynamically as well as for the static analysis.

Finally, I can't find any indication that type parameters are added to any scopes. We do get a specification that there is a scope for them (Sect. Classes):

A class has several scopes:
\begin{itemize}
\item A {\em type-parameter scope}, which is empty if the class is not generic
  (\ref{generics}). The enclosing scope of the type-parameter scope of a class is
  the enclosing scope of the class declaration.
\item A {\em static scope}. The enclosing scope of the static scope of a  class is
  the type parameter scope (\ref{generics}) of the class.
\item  An {\em instance scope}. The enclosing scope of a class' instance scope is
  the class' static scope.
\end{itemize}

This means that the usual problem with other scopes is avoided: Since we don't add type parameters to any scopes we don't have a name clash between the type parameter as such and a getter with return type Type. But if we fill in that missing information we'd need a similar solution. ;-)

Support method/function overloads

This has been discussed periodically both in the issue tracker and in person, but I don't think there's a tracking issue yet. (EDIT: Here is the original issue from 2011 - dart-lang/sdk#49).

Now that we're moving to a sound type system, we have the ability to overload methods—that is, to choose which of a set of methods is called based on which arguments are passed and what their types are. This is particularly useful when the type signature of a method varies based on which arguments are or are not supplied.

Optional auto-generation of operator== and hashCode on classes with const constructors

It is a common Dart idiom to have a class with all-final fields, a const constructor, a toString, an operator==, and a hashCode function.

The latter two are boilerplate:

  @override
  bool operator ==(dynamic other) {
    if (other.runtimeType != runtimeType)
      return false;
    final T typedOther = other;
    return typedOther.field1 == field1
        && typedOther.field2 == field2
        && typedOther.fieldN == fieldN;
  }

  @override
  int get hashCode => hashValues(field1, field2, fieldN);

It would be nice if there was some syntax or shorthand we could provide that would automatically provide these.

cc @abarth

Add a function pipe operator

This issue was originally filed by @chalin


Both AngularDart and Polymer have special syntax in support of function pipes (for Filters and Transformers) through the pipe | (bar) operator. E.g.

    person.lastName | uppercase

It would seem a natural fit for Dart to have native support for such a pipe operator. A case for the addition of a pipe operator in Dart is given here: http://pchalin.blogspot.com/2014/02/case-for-pipe-operator-in-dart.html

As is mentioned in the blog entry, I believe that added support should be considered for function composition operators (forward and/or reverse) as well.

Allow a `library` directive without a name

Several tools depend on the ability to add some metadata (@annotation) at a file level.

With the test package you can write

@Skip()
library my_test;

import 'package:test/test.dart';

Or

@Skip()

import 'package:test/test.dart';

The second form, is kind of a hack. The @Skip() attribute is in fact attached to the first import directive.
It causes problems with auto-formatters that re-order or remove imports. (See dart-lang/test#517)

The first form is safer but it requires to write a name for the library.
The linter recommends the name to be of the form package_name.test.path.to.file (http://dart-lang.github.io/linter/lints/package_prefixed_library_names.html).
This rule is necessary to avoid a warning because 2 libraries have the same name.
But this is tedious to write and to maintain.

I would like to write either:

@Skip()
library;

import 'package:test/test.dart';

Or that the analyzer doesn't report warnings if 2 libraries are named _. So I can write

@Skip()
library _;

import 'package:test/test.dart';

Extensible pattern-matching

This issue was originally filed by [email protected]


It would be nice to match a value against patterns with a terse syntax.

This is similar to 'switch' (and could possibly share the same syntax) but instead of exact-match, the semantics would be determined by the pattern used.

When the pattern is a RegExp, it would match strings that conform to it.
A Type would match instances of that type.
User classes should be able to implement their own pattern behaviour.
Any value without special pattern behaviour would match using ==

for example:

switch (value) {
  match Exception: throw value;
  match const RegExp('\s+') return 'whitespace';
  match 42: return 'the answer';
  default: return 'unrecognized';
}

There was some discussion here: https://groups.google.com/a/dartlang.org/group/misc/browse_thread/thread/a3e75c24c6dd4f03/

A pattern might also be able provide values which can be bound to names (e.g. the Match object corresponding to a regexp match).

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.