1

Is it possible to assign a type to a variable and then use that to create a type-based object, such as a List? My use case is that I have a Flutter widget using a particular data type to create a List for a FutureBuilder. If I could parameterise the type rather than hard-coding it then I could re-use the widget for multiple data types.

I have tried to do this in DartPad as follows:

void main() {
  A a = A(int);
  a.stuff();
}

class A {
  A(Type type) {
    _type = type;
  }
  late Type _type;

  void stuff() {
    print('$_type');     // prints out 'int'
    List<_type> b = [];
  }
}

If I comment out the line List<_type> b = []; then the code works and the output is int.

However, if I include the List<> line then I get the error "The name '_type' isn't a type so it can't be used as a type argument."

If have found next to nothing on the internet about this so think it might not be possible.

I have also had a look at the question on stack overflow here, which seems to be a similar question. This uses generics, which I know nothing about, and I couldn't make it work in my case. Is this a similar problem to mine and is it worth me doing some more exploration down this path?

My other idea was to pass a specific instance of the type that I want and then use runtimeType to get the type. I have tried this in Dart and it also gives an error.

void main() {
  A a = A(1);
  a.stuff();
}

class A {
  A(this.value){}
  dynamic value;

  void stuff() {
    print('${value.runtimeType}');     // prints out 'int'
    List<value.runtimeType> b = [];
  }
}

If I comment out the List<> line then the code outputs int.

However, with the list line uncommented, it gives the error "'type.runtimeType' can't be used as a type because 'type' doesn't refer to an import prefix."

Does anyone know if it possible to do what I want? Thanks.

Here is the full code for my use-case. I have commented the line that I would like to be able to parameterise somehow so that I can re-use the widget for different data sets with the same structure.

import 'package:drift/drift.dart' as drift;
import 'package:flutter/material.dart';
import 'package:frequent/database/tables.dart';
import 'package:frequent/maintain/change_record_widget.dart';
import 'package:frequent/maintain/change_record.dart';

class MaintainInstruments extends StatefulWidget {
  MaintainInstruments({
    Key? key,
    required String title,
    required MyDatabase database,
  }) : super(key: key) {
    _title = title;
    _db = database;
  }

  late final String _title;
  late final MyDatabase _db;

  @override
  State<MaintainInstruments> createState() => _MaintainInstrumentsState();
}

class _MaintainInstrumentsState extends State<MaintainInstruments> {
  final double _width = 300;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        centerTitle: true,
        title: Text(
          widget._title,
        ),
      ),
      //
      // Is it possible to parameterise the following statement so that I can
      // re-use this widget for a variety of data types that follow the same
      // format (id, name)?
      //
      body: FutureBuilder<List<InstrumentData>>(
        future: _getInstruments(widget._db),
        builder: (context, values) {
          return Center(
            child: Container(
              decoration: BoxDecoration(
                border: Border.all(),
                // color: Colors.blueGrey,
                borderRadius: const BorderRadius.all(Radius.circular(5)),
              ),
              child: Table(
                defaultColumnWidth: const IntrinsicColumnWidth(),
                children: [
                  TableRow(
                    children: [
                      TableCell(
                        child: SizedBox(
                          height: 300,
                          width: _width,
                          child: ListView.builder(
                            itemCount: values.hasData ? values.data!.length : 0,
                            itemBuilder: (context, index) {
                              return Card(
                                child: ListTile(
                                  title: Text(values.data![index].name),
                                  tileColor: Colors.amber[200],
                                  hoverColor: Colors.amber[400],
                                  dense: true,
                                  onTap: () {},
                                  trailing: SizedBox(
                                    width: _width * 0.2,
                                    child: Row(
                                      children: [
                                        Expanded(
                                          child: IconButton(
                                            iconSize: 20,
                                            icon: const Icon(Icons.edit),
                                            onPressed: () {
                                              showDialog<Record>(
                                                context: context,
                                                builder:
                                                    (BuildContext context) {
                                                  return ChangeRecord(
                                                    record: Record.instrument(
                                                      id: values
                                                          .data![index].id,
                                                      instrument: values
                                                          .data![index].name,
                                                    ),
                                                  );
                                                },
                                              ).then((value) {
                                                setState(() {
                                                  _updateInstrument(
                                                      widget._db,
                                                      value!.id,
                                                      value.instrument);
                                                });
                                              });
                                            },
                                          ),
                                        ),
                                        Expanded(
                                          child: IconButton(
                                            iconSize: 20,
                                            icon: const Icon(Icons.delete),
                                            onPressed: () {
                                              setState(() {
                                                _deleteInstrument(widget._db,
                                                    values.data![index].id);
                                              });
                                            },
                                          ),
                                        ),
                                      ],
                                    ),
                                  ), // Just to track mouse over cards
                                ),
                              );
                            },
                          ),
                        ),
                      ),
                    ],
                  ),
                ],
              ),
            ),
          );
        },
      ),
    );
  }
}

Future<List<InstrumentData>> _getInstruments(MyDatabase db) async {
  List<InstrumentData> values = await (db.select(db.instrument)
        ..orderBy([(t) => drift.OrderingTerm(expression: t.name)]))
      .get();
  return values;
}

void _deleteInstrument(MyDatabase db, int id) {
  (db.delete(db.instrument)..where((tbl) => tbl.id.equals(id))).go();
}

_updateInstrument(MyDatabase db, int id, String value) {
  (db.update(db.instrument)..where((tbl) => tbl.id.equals(id)))
      .write(InstrumentCompanion(name: drift.Value(value)));
}
3
  • you are getting error because you are doing it wrong. it should be List<Type>. inside that bracket is a type annotation not an instance. Commented Oct 18, 2022 at 15:08
  • Sure, I get that. My question isn't, "why am I getting this error?" It is, "can you define the type at run time rather than at compile time, for example by using a variable?" (or using a design pattern etc.) Commented Oct 19, 2022 at 10:58
  • of course you can. by assigning a variable to a type of 'var` you are saying that the compiler will give an explicit type on run time. take note that dart is a strongly typed language. and you can not run a variable without giving a type. Commented Oct 19, 2022 at 11:16

2 Answers 2

3

Dart supports generic types. SO you can do something like

class A<T> {

  void stuff() {
    List<T> b = [];
  }
}

And use it as

A<int>, A<String>

whatever type you need

Sign up to request clarification or add additional context in comments.

8 Comments

Thanks for rhe quick response, but I don't think that answers my question. If I create a variable Type t and use that in A<t> I get the same error as I do in the first example above, i.e. "The name 't' isn't a type so it can't be used as a type argument." If I use 'T' in my Flutter code for the FutureBuilder (FutureBuilder<List<T>>) then I get the same error.
Can you post the code for error you got with generic types
This is the message in Visual Studio Code: "The name 'T' isn't a type so it can't be used as a type argument. Try correcting the name to an existing type, or defining a type named 'T'. dart(non_type_as_type_argument)"
please post your code
@Twelve1110 yes you are right
|
0

you can use generics as this example :

class A<T> {
  List<T> stuff() {
    List<T> b = [];
    return b;
  }
}

then when you want to call this :

A a = A<int>();
List c = a.stuff();

this is a simple demo to understand the generic.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.