New expression cannot be invoked on type variable

217 views
Skip to first unread message

John McCutchan

unread,
May 5, 2012, 3:26:48 PM5/5/12
to General Dart Discussion
Hey,

I'm attempting to do something like:

class Table<E> {
  List<E> _objects;

  Table(int MaxObjects) {
    _objects = new List<E>(maxObjects);
    for (int i i = 0; i < maxObjects; i++) {
      _objects[i] = new E(); /* ! */
    }
  }
}

The editor infers the error "New expression cannot be invoked on type variable" and Dartium gives me:

type parameter 'E' cannot be instantiated

      _objects[i] = new E();

                                   ^

Is this a bug or by design? More importantly- How can I express this in Dart?

--
John McCutchan <jo...@johnmccutchan.com>

Stephen Adams

unread,
May 5, 2012, 3:34:24 PM5/5/12
to John McCutchan, General Dart Discussion
This is by design.  I don't recall why.
You can work around the issue by passing a function:

class Table<E> {
  List<E> _objects;

  Table(int MaxObjects, E create()) {
    _objects = new List<E>(maxObjects);
    for (int i = 0; i < maxObjects; i++) {
      _objects[i] = create(); /* ! */
    }
  }
}

var table = new Table<Widget>(100, () => new Widget());

 
--
John McCutchan <jo...@johnmccutchan.com>

Dirk Detering

unread,
May 6, 2012, 4:24:58 AM5/6/12
to Stephen Adams, John McCutchan, General Dart Discussion

Am 05.05.2012 21:34 schrieb "Stephen Adams" <s...@google.com>:
>> class Table<E> {
>>   ...


>>     for (int i i = 0; i < maxObjects; i++) {
>>       _objects[i] = new E(); /* ! */

> This is by design.  I don't recall why.

Simple answer: Darts type system is an optional type system. Types are annotations and the runtime semantics don't change if you leave them away.
So leave <E> away. What shall be constructed?

Even more, E is a type _variable_ and thus can refer to any possible type depending on the call site. There's no guarantee that an empty constructor even exists for all possible types in E.

John McCutchan

unread,
May 6, 2012, 12:13:30 PM5/6/12
to Dirk Detering, Stephen Adams, General Dart Discussion
Hi Dirk,

I expected this answer and I understand it. But, it's awkward. Coming from a C++ background I expected Dart type variables to behave like template parameters in C++. By using the same syntax and sharing some of the semantics as C++/C# generics, new Dart developers are likely to be confused and disappointed. 

This broke my flow. I spent time googling, trying silly things to see if I could get the compiler to just "take it" and ultimately came up with the same workaround that Stephen suggested. So, now I have to specify type information twice:

typedef Object TableElemenetConstructor()

class<E> Table {
  Table(int maxObjects, TableElementConstructor);
};

Foo FooConstructor() => new Foo

Table<Foo> t = new Table(1024, FooConstructor);

That's some hoops to jump through.

The more I write Dart the more I wish that the type system was part of the cake and not just the icing.

John
--
John McCutchan <jo...@johnmccutchan.com>

Ladislav Thon

unread,
May 6, 2012, 2:22:12 PM5/6/12
to Dirk Detering, Stephen Adams, John McCutchan, General Dart Discussion

Simple answer: Darts type system is an optional type system. Types are annotations and the runtime semantics don't change if you leave them away.
So leave <E> away. What shall be constructed?

Actually, there are two places (that I know of) where type annotations _do_ affect runtime semantics in Dart: the catch clause of try/catch statement (only objects of given type are caught) and generics (if you instantiate a parameterized type, the type arguments are preserved and you can refer to them at runtime). Both of them live just fine without type annotations (and the behavior is pretty carefully crafted); with regards to generics, if <E> is omitted, it's the same as if <Dynamic> is written.

Even more, E is a type _variable_ and thus can refer to any possible type depending on the call site. There's no guarantee that an empty constructor even exists for all possible types in E.

In C#, you can specify that a type argument must have a constructor. In Dart, type arguments can only have an upper bound (<T extends Something>), but there could be other bounds (for constructors, something like <T is new> or <T is new & extends Something>; named constructors could be specified too like <T is new.namedCtor>). This way, you could express your intention that the type argument will be instantiated, but it isn't really needed for it to work (and I don't expect the Dart team to increase complexity of already complex generics).

In principle, nothing prevents type arguments to be instantiated already -- the runtime would simply find a matching constructor (that involves constructor names and a number of arguments) and invoke it. For sake of type argument instantiation, the Dynamic type would never have a matching constructor.

If you take a look at chapter 9 of the specification, a non-normative text at the and says:

Even where type parameters are in scope there are numerous restrictions at this time:

A type parameter cannot be used to name a constructor in an instance creation expression.
A type parameter cannot be used as an identifier  expression.
A type parameter cannot be used as a superclass or superinterface.

The normative versions of these are given in the appropriate sections of this specification. Some of these restrictions may be lifted in the future.

The bold highlighting is mine.

LT

Sam McCall

unread,
May 6, 2012, 2:23:11 PM5/6/12
to Dirk Detering, John McCutchan, General Dart Discussion, Stephen Adams

Dirk, as I understand that's not actually true, dart's generics are reified (unlike in java); you can say "x is List<num>" which will be true if x was constructed with 'num' as the type parameter.
Dart also seems to have raw types for both values and type annotations (List x = new List()).
To me these combinations of features (optional typing + reified generics, reified generics + raw types) are pretty confusing!

You're right that the constructor can't be verified to exist, and this may be the reason you can't instantiate a type variable - constructors act like static methods and must be resolvable statically.

Ross Smith

unread,
May 6, 2012, 2:50:28 PM5/6/12
to General Dart Discussion
As Ladislav mentioned this is possible in C# but with a confusing
syntax (re-purposing of the new keyword):

class ItemFactory<T> where T : new() { }

Then ItemFactory can then safely use 'new T()' in its code.

Personally, I hope this level of complexity doesn't go into dart - at
first I missed a lot of stuff from other language generics in coming
to dart but i've grown to really appreciate that 'icing' and forgot
about the 'cake' :)

-Ross


On May 6, 2:23 pm, Sam McCall <sammcc...@google.com> wrote:
> Dirk, as I understand that's not actually true, dart's generics are reified
> (unlike in java); you can say "x is List<num>" which will be true if x was
> constructed with 'num' as the type parameter.
> Dart also seems to have raw types for both values and type annotations
> (List x = new List()).
> To me these combinations of features (optional typing + reified generics,
> reified generics + raw types) are pretty confusing!
>
> You're right that the constructor can't be verified to exist, and this may
> be the reason you can't instantiate a type variable - constructors act like
> static methods and must be resolvable statically.

Dirk Detering

unread,
May 7, 2012, 12:33:42 AM5/7/12
to Sam McCall, John McCutchan, General Dart Discussion, Stephen Adams

Am 06.05.2012 20:23 schrieb "Sam McCall" <samm...@google.com>:
>
> Dirk, as I understand that's not actually true, dart's generics are reified (unlike in java); you can say "x is List<num>" which will be true if x was constructed with 'num' as the type parameter.

Well, ok, I consider type and class to be not fully equivalent. So I supposed access to type _information_ (is List<num>) different from access to the _class_ that implements it.

That came from the fact that in List<E> the E could refer to an interface which not necessarily would be backed by a default class.

> Dart also seems to have raw types for both values and type annotations (List x = new List()).
> To me these combinations of features (optional typing + reified generics, reified generics + raw types) are pretty confusing!
>

I share this confusion.

> You're right that the constructor can't be verified to exist, and this may be the reason you can't instantiate a type variable - constructors act like static methods and must be resolvable statically.
>

That' what I thought.

Bob Nystrom

unread,
May 7, 2012, 1:55:52 PM5/7/12
to Dirk Detering, Stephen Adams, John McCutchan, General Dart Discussion
I think you guys have covered all of the salient points in this thread. Thanks!

One clarification:

Types are annotations and the runtime semantics don't change if you leave them away.

Types aren't always annotations. There are type annotations, but there are also places where types appear in code that are not annotations. For example:

// type annotations:
int i;
foo(int i) => ...
class Foo {
  int bar;
  int baz() => ...
}

// types that are not annotations:
foo is String;
new Foo();
new Foo<Bar>();
class Foo extends Bar implements Baz { ... }
catch (SomeException ex) { ... }

In every place where a type appears outside of an annotation, the type absolutely does have an important affect at runtime, and cannot be ignored. It's only type annotations that are "optional" in that sense.

Cheers!

- bob

Eli Brandt

unread,
May 7, 2012, 3:55:43 PM5/7/12
to Bob Nystrom, Dirk Detering, Stephen Adams, John McCutchan, General Dart Discussion
On Mon, May 7, 2012 at 10:55 AM, Bob Nystrom <rnys...@google.com> wrote:
I think you guys have covered all of the salient points in this thread. Thanks!

One clarification:

Types are annotations and the runtime semantics don't change if you leave them away.

Types aren't always annotations. There are type annotations, but there are also places where types appear in code that are not annotations. For example:


And as Bob has commented on in the past, I find it clearer in my head to pretend that we use a Pascal-style syntax for type annotation.  Then the type annotations are wherever you could imagine writing that syntax.
 
// type annotations:
int i;
foo(int i) => ...
class Foo {
  int bar;
  int baz() => ...
}

Which make sense imagined as
i: int
foo(i: int)
class Foo { bar: int; ... }
 

// types that are not annotations:
foo is String;
new Foo();
Whereas here you wouldn't try to write
new (): Foo 
and probably not
if (foo: String)
either.
new Foo<Bar>();
class Foo extends Bar implements Baz { ... }
catch (SomeException ex) { ... }


Here's the annoying exception, I for one *could* imagine writing this like an annotation
catch (ex: SomeException)
but it isn't one.

Eli

Sam McCall

unread,
May 7, 2012, 4:39:37 PM5/7/12
to Eli Brandt, Bob Nystrom, Dirk Detering, Stephen Adams, John McCutchan, General Dart Discussion
On Mon, May 7, 2012 at 12:55 PM, Eli Brandt <e...@google.com> wrote:
> Here's the annoying exception, I for one *could* imagine writing this like
> an annotation
>
> catch (ex: SomeException)
>
> but it isn't one.

The C++ catch syntax looks a lot like function declaration syntax,
with the exception as a parameter. This works well because the type is
used for pattern-matching in both cases.

In Dart with no method overloading, this pun is misleading. What about
making it look like dart's other pattern matching constructs instead?

try {
doSomethingDangerous();
} except (e is SomeException) {
print(e);
} finally {
cleanUp();
}

Ladislav Thon

unread,
May 8, 2012, 3:44:12 AM5/8/12
to Bob Nystrom, Dirk Detering, Stephen Adams, John McCutchan, General Dart Discussion
// types that are not annotations:
foo is String;
new Foo();
new Foo<Bar>();
class Foo extends Bar implements Baz { ... }
catch (SomeException ex) { ... }

Note that out of these five situations, two are slighly confusing. They are those two I've already mentioned. If you can write new Foo<Bar>(), you can omit the type parameter and write new Foo(), which then means the same as new Foo<Dynamic>(). If you can write catch (SomeException e), then you can write catch (var e).

In these two situations, types are still somewhat optional, and that is what confuses people (I remember being confused at least about the catch clause). The other situations are clear, they wouldn't make any sense without types.

LT

Seth Ladd

unread,
May 8, 2012, 11:00:37 AM5/8/12
to Ladislav Thon, Bob Nystrom, Dirk Detering, Stephen Adams, John McCutchan, General Dart Discussion
I think we need to be more clear and draw a distinction between "optional" and "has no runtime semantics in production mode". In the two cases you mention below, Foo<Bar> and catch(SomeException e), the program's runtime semantics are affected, even in production mode. A developer might choose not to include extra type syntax, but the runtime behavior of the program is different than simply saying Foo() and catch(final e).

Ladislav Thon

unread,
May 8, 2012, 11:08:00 AM5/8/12
to Seth Ladd, Bob Nystrom, Dirk Detering, Stephen Adams, John McCutchan, General Dart Discussion
I think we need to be more clear and draw a distinction between "optional" and "has no runtime semantics in production mode". In the two cases you mention below, Foo<Bar> and catch(SomeException e), the program's runtime semantics are affected, even in production mode.

Yeah, I think that better education is the correct solution here.

LT

Seth Ladd

unread,
May 8, 2012, 12:22:02 PM5/8/12
to Ladislav Thon, Bob Nystrom, Dirk Detering, Stephen Adams, John McCutchan, General Dart Discussion
Will do. We have a new round of presentations coming up, this is good feedback. Thanks for your help here.

Eli Brandt

unread,
May 8, 2012, 1:53:58 PM5/8/12
to Sam McCall, Bob Nystrom, Dirk Detering, Stephen Adams, John McCutchan, General Dart Discussion
This would make look good to me.  File an issue and see what other people think?

Eli

Ladislav Thon

unread,
May 8, 2012, 3:38:44 PM5/8/12
to Eli Brandt, Dirk Detering, John McCutchan, Bob Nystrom, General Dart Discussion, Stephen Adams, Sam McCall


>> try {
>>  doSomethingDangerous();
>> } except (e is SomeException) {
>
>
> This would make look good to me.  File an issue and see what other people think?

I was thinking about it and concluded that in this edge case, it probably isn't worth losing the familiar syntax. This can cause other types of confusion -- are all bool-returning expressions allowed here, or only 'is'?

On the other hand, should this change happen, I wouldn't oppose it.

LT

Dirk Detering

unread,
May 8, 2012, 4:06:54 PM5/8/12
to Ladislav Thon, Bob Nystrom, John McCutchan, General Dart Discussion, Sam McCall, Stephen Adams, Eli Brandt


Am 08.05.2012 21:38 schrieb "Ladislav Thon" <lad...@gmail.com>:
>
>
> >> try {
> >>  doSomethingDangerous();
> >> } except (e is SomeException) {

> I was thinking about it and concluded that in this edge case, it probably isn't worth losing the familiar syntax. This can cause other types of confusion -- are all bool-returning expressions allowed here, or only 'is'?
>

That is the reason I long for pattern matching or the like:

} catch (e) {
      case e is SomeException : ....
      case e ..... : ....

Try-catch intermingled with some sort of switch mechanism, which btw works only for a catch (like with Java) was a bad idea in my eyes.
It may only be me, but my question is where it is worth to _keep_ the familiar syntax. (Where "familiar" seems implicitly to be "Java" quite often).

That is why I like Scala: Good separation of concerns paired with combinability of features. Feels so ... Unixy.

Sam McCall

unread,
May 8, 2012, 4:43:11 PM5/8/12
to Eli Brandt, Bob Nystrom, Dirk Detering, Stephen Adams, John McCutchan, General Dart Discussion
Filed http://code.google.com/p/dart/issues/detail?id=2948

Agreed about that syntax looking like a boolean expression, and that
pattern matching would be better. I still think it's an improvement.

I'll see if there's a pattern matching bug already...

Sam McCall

unread,
May 8, 2012, 5:18:55 PM5/8/12
to Eli Brandt, Bob Nystrom, Dirk Detering, Stephen Adams, John McCutchan, General Dart Discussion
On Tue, May 8, 2012 at 1:43 PM, Sam McCall <samm...@google.com> wrote:
> Filed http://code.google.com/p/dart/issues/detail?id=2948
>
> Agreed about that syntax looking like a boolean expression, and that
> pattern matching would be better. I still think it's an improvement.
>
> I'll see if there's a pattern matching bug already...
Filed http://code.google.com/p/dart/issues/detail?id=2949 on pattern-matching.

Ladislav Thon

unread,
May 9, 2012, 1:41:53 AM5/9/12
to Sam McCall, Dirk Detering, John McCutchan, Bob Nystrom, General Dart Discussion, Stephen Adams, Eli Brandt


> > Agreed about that syntax looking like a boolean expression, and that
> > pattern matching would be better. I still think it's an improvement.
> >
> > I'll see if there's a pattern matching bug already...
> Filed http://code.google.com/p/dart/issues/detail?id=2949 on pattern-matching.

I'd love to have pattern matching in Dart, but I sincerely hope that it wouldn't be like a switch, its syntax (with breaks and fallthrough) is terrible. But I know that Dart people are aware of that, so I'm not worried :-)

LT

Sam McCall

unread,
May 9, 2012, 2:09:06 AM5/9/12
to Ladislav Thon, Dirk Detering, John McCutchan, Bob Nystrom, General Dart Discussion, Stephen Adams, Eli Brandt
+1
Reply all
Reply to author
Forward
0 new messages