Sdk: Construction of generic types "new T()"

Created on 5 Jul 2017  路  10Comments  路  Source: dart-lang/sdk

With strong mode becoming the default in 2.0
I was wondering if it would then be possible to add support for calling constructors based on generic types?

T Create<T>(){
 return new T();
}

An example use case would be.

import 'dart:typed_data';

class VertexList<T>{
  Float32List vertexData;
  int vertexSize;

  VertexList(){
    vertexSize = T.vertexSize;
  }

  T getAt(int i){
    var offset = i * vertexSize;
    return new T.fromView(new Fload32List.view(vertexData.buffer, offset, offset + vertexSize));
  }

}

class MyVertex{
  static int vertexSize = 8;

  Vector3 position;
  Vector3 normal;
  Vector2 uv;

  MyVertex.fromView(Float32List view){
    position = new Vector3.fromView(view);
    normal = new Vector3.fromView(view);
    uv = new Vector2.fromView(view);
  }
}

class NotVertexClass{
}

/// usage
var list = new VertexList<MyVertex>(); // This is good!
var badList= new VertexList<NotVertexClass>(); // Error: NotVertexClass does not have constructor fromView

list.getAt(0).position.x = 10.0;
area-language closed-not-planned type-enhancement

All 10 comments

There is the obvious problem, which you also point out, that there is no static way to know which constructors a the type of a type parameter supports.
That can mean either getting constructor errors as runtime errors, with no static checking, or somehow constrain type parameters to classes with the desired constructors (specified in some way).

In C#, you can require a type parameter to have a zero-argument constructor, but you can't pass any parameters. In Dart, that would correspond to only allowing zero-argument unnamed constructors to be used. That wouldn't allow your T.fromView above.

If you have to handle named constructors or constructors with arguments differently anyway, I'm not sure I think the feature is worth it.

I get your point. I guess you'd have to introduce abstract named constructors? (Not sure if possible) And require T extends SomeAbstract class.

class VertexList<T extends Vertex>{
  Float32List vertexData;
  int vertexSize;

  VertexList(){
    vertexSize = T.vertexSize;
  }

  T getAt(int i){
    var offset = i * vertexSize;
    return new T.fromView(new Fload32List.view(vertexData.buffer, offset, offset + vertexSize));
  }

}

abstract Vertex{
  Vertex.fromView(Float32List view); /// Abstract constructor?
}

class MyVertex extends Vertex{
  static int vertexSize = 8;

  Vector3 position;
  Vector3 normal;
  Vector2 uv;

  MyVertex.fromView(Float32List view){
    position = new Vector3.fromView(view);
    normal = new Vector3.fromView(view);
    uv = new Vector2.fromView(view);
  }
}

This would mean potentially retaining constructor information for _all_ Types, which is a major no-no for ahead-of-time compilation that needs tree-shaking and dead code elimination. This should probably be a "wontfix" @lrhn

We definitely do not want type parameters to carry static members in general (constructors are somewhere between static members and instance members). To make that useful, we'd have to make "static interfaces" that abstracts over a number of static classes, and then the classes basically just become a bunch of singleton objects.
Even doing it just for nameless parameterless constructors seems like more complication than it's worth. If you need something to abstract over the ability to create objects, you can just make it accept a factory function as argument along with the type parameter.

Closing per the above comments.

It works in C++, and C++ is compiled, so...?

template<class T>
struct Foo {
    static void test() {
        T::some_method();
    }
};

Closing per the above comments.

We're going to close this feature request, even though we have unanimous 13-0 votes on the parent comment?

Edit: #34131 and also a unanimous 0-13 downvotes here...

That's a C++ template, which is quite different from anything in Dart.
C++ expands all templates at compile time, then checks whether the result is valid. You an instantiate this template with any type for which T::some_method() would be valid.

Dart generics are retained at run-time, as run-time parameters of the instances. We still want to statically detect errors, so we can't just allow you to pass any type without somehow ensuring that it will work everywhere that the type parameter flows.
That's why we need interfaces (C++ does not have interfaces), so that we can say that an object satisfies at least that interface, so you can safely use those interface methods.

In order to allow new T we would need the type to satisfy some "type interface", which is a completely new concept.

It's just not a good match for an interface based, run-time generic language like Dart.

In that case, what about something like this?

class Foo<T extends BaseClass> {
    static void bar() {
        T.baz();
    }
}
class BaseClass {
    static void baz() {
    }
}

If T extends BaseClass then T.baz() must always be valid.

Dart does not inherit static members, so a subclass of BaseClass is not guaranteed to have a static baz member.

Ah, true. In that case, https://github.com/dart-lang/language/issues/356
I did solve this with reflection, but that's only temporary

Was this page helpful?
0 / 5 - 0 ratings

Related issues

55555Mohit55555 picture 55555Mohit55555  路  3Comments

matanlurey picture matanlurey  路  3Comments

xster picture xster  路  3Comments

ranquild picture ranquild  路  3Comments

DartBot picture DartBot  路  3Comments