Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Operator '[]=' for the class 'Object' #543

Closed
LeoDoldan7 opened this issue Aug 24, 2019 · 5 comments
Closed

Operator '[]=' for the class 'Object' #543

LeoDoldan7 opened this issue Aug 24, 2019 · 5 comments

Comments

@LeoDoldan7
Copy link

LeoDoldan7 commented Aug 24, 2019

Problem

AFAIK, something like the following is impossible to implement:

class Updater<T> {
  T entity;

  Updater(this.entity);

  update(String key, dynamic value) {
    entity[key] = value;
  }
}

Because the following error is thrown:

The operator '[]=' isn't defined for the class 'Object'.
Try defining the operator '[]='.

Request

Please, implement the operator '[]=' for the class 'Object'.

Regarding typing, this is a simple TypeScript-like suggestion:

class Updater<T> {
  T entity;

  Updater(this.entity);

  update<K keyof T>(K key, dynamic value) {
    entity[key] = value;
  }
}

Thank you!

@lrhn
Copy link
Member

lrhn commented Aug 26, 2019

The Object class does not have any [] operator. I am assuming you want a behavior similar to JavaScript, but Dart is not JavaScript. You cannot look up members using [] and a string name o["foo"], you have to write o.foo.
This is a deliberate choice, and if you want to access a member by a name that is only known as a string at runtime, that is reflection and you need to use dart:mirrors for it (on a platform supporting dart:mirrors).

There are no plans to allow reflection directly on Object.

Aside from that, it would break every other class which currently extend Object and implement operator[] (like Map).

@lrhn lrhn closed this as completed Aug 26, 2019
@rakudrama
Copy link
Member

@LeandroDoldan Something like this might work for you:

// T is the type of things held, instead of the type of the collection.
class Updater<T> {
  Map<String, T> entity;
  Updater(this.entity);
  update(String key, T value) {
    entity[key] = value;
  }
}

You could write dynamic code that is against the spirit of Dart. I would advise against this - dynamic invocation is often less efficient and you get no safety or code completion benefits that you would get with stronger typing.

class Updater<T> {
  T entity;
  Updater(this.entity);
  update(String key, T value) {
    (entity as dynamic)[key] = value;
  }
}

I do think it is an interesting idea to 'destructure' the type. If Dart had that feature it might look like

class Updater<T extends Map<K, V>> {
  T entity;
  Updater(this.entity);
  update(K key, V value) {
    entity[key] = value;
  }
}

@lrhn Sometimes it is awkward to 'pass around' several types as type parameters, perhaps the language could support that better.

@eernstg
Copy link
Member

eernstg commented Aug 26, 2019

@rakudrama, just FYI, the 'destructure the type' feature is at the core of the type patterns proposal (#170).

That proposal is intended to be used by other constructs, e.g., a pattern matching is test that would amount to an 'existential open' operation:

void foo(Object x, Object y, Object z) {
  if (x is Map<var K, var V>) {
    // K, V denote exactly the value of the type arguments to the type of `x` at `Map`,
    // so this is safe:
    if (y is K && z is V) x[y] = z;
  }
}

A similar operation for the relationship between types could certainly be provided (X isSubtypeOf Map<var K, var V> where X is a type variable would evaluate to true when such a subtype relationship exists for any K and V, and it would bind K and V to the actual type arguments of X at Map).

In the end we did not use type patterns for extension methods, but extension methods are still similar. (Basically, we didn't need type patterns because we decided to match extension type arguments with the statically known values, not the dynamic ones, and then the job can be done using standard type inference.) So you can use extensions for some static cases:

extension Updater<K, V> on Map<K, V> {
  void myUpdate(K key, V value) => this[key] = value;
}

main() {
  Map<int, int> map = {};
  map.myUpdate(3, 4);
}

This would also work in the case where the type of map is some subtype of Map where you cannot see the type arguments for Map directly (say, class C extends Map<int, int> {...}), and it does decompose the type in the sense that it allows us to refer to K and V as types in a scope which is outside the declaration of Map (and also outside the body of its subtypes where we could also have access to K and V).

@mraleph
Copy link
Member

mraleph commented Aug 26, 2019

@LeandroDoldan

AFAIK, something like the following is impossible to implement:

I think the question that we should first and foremost ask here is: why do you want such pattern in the first place?

Can you give a larger example on how you are planning to use such Updater class?

@Levi-Lesches
Copy link

@Vatsboy, your error isn't related to this issue. Try posting it on StackOverflow.com for an explanation of your error.

@dart-lang dart-lang deleted a comment from Vatsboy Oct 1, 2021
@dart-lang dart-lang deleted a comment from Vatsboy Oct 1, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants