BreezyChick89
BreezyChick89

Reputation: 1479

Is there anything like a struct in dart?

In javascript it always bothered me people use objects as vectors like {x: 1, y: 2} instead of using an array [1,2]. Access time for the array is much faster than the object but accessing by index is more confusing especially if you need a large array. I know dart has fixed arrays but is there a way to name the offsets of an array like you would a struct or a tuple/record in another language? Define enum/constants maybe?

I'd want something like

List<int> myVector = new List([x,y]);
myVector.x = 5;

is there an equivalent or idiomatic way to do this?

Upvotes: 48

Views: 40967

Answers (7)

Alireza Soltani Neshan
Alireza Soltani Neshan

Reputation: 351

In Dart version 3, you can define Record types. Based on dart document. Another pattern is typedef. By combining of typedef and Record you can write a special interface like Typescript language (Not as object).

I think it's more clear compare with class way.

(Edit: Yes I know that, we use classes for define our objects and instances, also I know using tuples have proper time. But when you want create a simple structure to define some UI in dynamic way you may need to define following approach.)

typedef University = ({
  String name,
  String field,
  String grade,
});

typedef User = ({
  String name,
  int age,
  String address,
  University uni,
});

User person = (
 name: "Alireza",
 age: 22,
 address: "xyz",
 uni: (
   name: "Some",
   field: "Software",
   grade: "A+",
 ),
);

void main() {
 print(person.name);
 print(person.uni.name);
}

Upvotes: 6

lrn
lrn

Reputation: 71623

That sounds like a class.

 class MyVector {
   int x;
   int y;
   MyVector(this.x, this.y);
 }

There is no simpler and more efficient way to create a name-indexed structure at runtime. For simplicity you could usually use a Map, but it's not as efficient as a real class.

A class should be at least as efficient (time and memory) as a fixed length list, after all it doesn't have to do an index bounds check.

In Dart 3.0, the language will introduce records. At that point, you can use a record with named fields instead of creating a primitive class:

var myVector = (x: 42, y: 37);
print(myVector.x);

A record is unmodifiable, so you won't be able to update the values after it has been created.

Upvotes: 58

tanghao
tanghao

Reputation: 4571

The Tuple package https://pub.dev/packages/tuple might be what you are looking for when a class is too heavy.

import 'package:tuple/tuple.dart';

const point = Tuple2<int, int>(1, 2);

print(point.item1); // print 1
print(point.item2); // print 2

Upvotes: 0

Bouke Versteegh
Bouke Versteegh

Reputation: 4677

You could also use an extension on List to create aliases to specific indexes.

Although it will be difficult to set up mutually exclusive aliases, in some cases, it may be a simple solution.

import 'package:test/test.dart';

extension Coordinates<V> on List<V> {
  V get x => this[0];

  V get y => this[1];

  V get z => this[2];
}

void main() {
  test('access by property', () {
    var position = [5, 4, -2];
    expect(position.x, 5);
    expect(position.y, 4);
    expect(position.z, -2);
  });
}

Upvotes: 2

Vink
Vink

Reputation: 1277

For me, i see 2 way to do this. I will sort by best in my point of view

Class based method

Here, the approach is to encapsulate your need, in a dedicated object

Pros:

  • It's encapsultate
  • You can propose several way to access variable, depend of the need
  • You can extend functionality without break everything
  • I love it :p

Cons

  • More time spend to create class, etc.
  • Do you really need what i say in pros ?
  • Maybe weird for js people

example :

class Vector {
  int x;
  int y;

  static final String X = "x";
  static final String Y = "y";

  Vector({this.x, this.y});
  Vector.fromList(List<int> listOfCoor) {
    this.x = listOfCoor[0];
    this.y = listOfCoor[1];
  }

  // Here i use String, but you can use [int] an redefine static final member
  int operator[](String coor) {
    if (coor == "x") {
      return this.x;
    } else if (coor == "y") {
      return this.y;
    } else {
      // Need to be change by a more adapt exception :)
      throw new Exception("Wrong coor");
    }
  }
}

void main() {
  Vector v = new Vector(x: 5, y: 42);
  Vector v2 = new Vector.fromList([12, 24]);

  print(v.x); // print 5
  print(v["y"]); // print 42
  print(v2.x); // print 12
  print(v2[Vector.Y]); // print 24
}

Enum based method:

You can also defined a "enum" (actually not really implement but will be in the future version) that will contains "shortcut" to your value

Pros

  • More simple to implement
  • Is more like your example ;p

Cons

  • Less extendable
  • i think is not very pretty
  • Not OOP think

example:

class Vector {
  static final int x = 0;
  static final int y = 1;
}

void main() {
  List<int> myVector = new List(2);
  myVector[Vector.x] = 5;
  myVector[Vector.y] = 42;
}

Make your choice ;p

Upvotes: 7

JAre
JAre

Reputation: 4756

If you have reasonably big data structure, you can use "dart:typed_data" as a model and provide lightweight view for the stored data. This way the overhead should be minimal. For example, if you need 4X4 matrix of Uint8 values:

import "dart:typed_data";
import "dart:collection";
import "package:range/range.dart";
class Model4X4Uint8 {
  final Uint8List _data;
  static const int objectLength = 4 * 4;
  final Queue<int> _freeSlotIndexes;
  Model4X4Uint8(int length): _data = new Uint8List((length) * objectLength),
        _freeSlotIndexes = new Queue<int>.from(range(0, length));
  int get slotsLeft => _freeSlotIndexes.length;
  num operator [](int index) => _data[index];
  operator []=(int index, int val) => _data[index] = val;
  int reserveSlot() =>
      slotsLeft > 0 ? _freeSlotIndexes.removeFirst() : throw ("full");
  void delete(int index) => _freeSlotIndexes.addFirst(index);
}
class Matrix4X4Uint8 {
  final int offset;
  final Model4X4Uint8 model;
  const Matrix4X4Uint8(this.model, this.offset);
  num operator [](int index) => model[offset + index];
  operator []=(int index, int val) => model[offset + index] = val;
  void delete() => model.delete(offset);
}
void main() {
  final Model4X4Uint8 data = new Model4X4Uint8(100);
  final Matrix4X4Uint8 mat = new Matrix4X4Uint8(data, data.reserveSlot())
      ..[14] = 10
      ..[12] = 256; //overlow;
  print("${mat[0]} ${mat[4]} ${mat[8]} ${mat[12]} \n"
        "${mat[1]} ${mat[5]} ${mat[9]} ${mat[13]} \n"
        "${mat[2]} ${mat[6]} ${mat[10]} ${mat[14]} \n"
        "${mat[3]} ${mat[7]} ${mat[11]} ${mat[15]} \n");
  mat.delete();
}

But this is very low level solution and can easily create sneaky bugs with memory management and overflows.

Upvotes: 5

G&#252;nter Z&#246;chbauer
G&#252;nter Z&#246;chbauer

Reputation: 657158

This is only possible with a class in Dart.

There are some open feature requests at http://dartbug.com

Upvotes: 6

Related Questions