Discussion:
[dart-misc] How to control access to elements of collection properties?
Philipp S
2016-08-09 11:35:36 UTC
Permalink
Hey!

If I want to control access to a regular class property, I implement a
getter and setter for it. However, sometimes I have a class which exposes a
collection of elements through a property (in my example, `Basket.items`):
class Item {
Basket basket;
String name;
Item(this.basket, this.name);
}

class Basket {
final Map<String, Item> items = {};
void doStuffWithItems() { ... }
}

Let's say I want to create items on demand, and enforce relational
integrity between items and baskets; I can achieve this by wrapping
`Item.basket` with getters and setters, and implement explicit
`Basket.getItem` and `Basket.addItem` methods:
class Item {
Basket _basket;
String name;

Basket get basket => _basket;

void set basket(Basket basket) {
_basket._items.remove(name);
basket._items[name] = this;
_basket = basket;
}

Item._(this._basket, this.name);
}

class Basket {
final Map<String, Item> _items = {};

Item getItem(String name) =>
_items.putIfAbsent(name, () => new Item._(this, name));

void addItem(Item item) => item.basket = this;

...
}

This works, but the `getItem` and `setItem` methods feel inelegant and not
Dart-y.
Also, this way I lose the Map interface, so I can't do things like
`basket.items.keys.map(print)`. I can fix that too by adding an
`UnmodifiableMapView get items` to Basket, but now the API to obtain an
item is scattered over two different objects!

If anonymous classes were supported, I'd go with an anonymous
implementation of Map that overrides `operator []`:
class Basket {
final Map<String, Item> items = new Map<String, Item>() {
Item operator [](String name) =>
putIfAbsent(name, () => new Item(Basket.this, name)); //
`Basket.this` in Java captures the object scope of the surrounding class,
if you don't know (I didn't 10 minutes ago)
};

...
}

Since I've seen that anonymous classes are not supported and not planned,
and I couldn't come up with a clever google search query about my issue, I
thought I'd ask here. Does Dart have an established way to handle this use
case, and if not, what are your preferences and experiences? Do you prefer
* `getItem`, `setItem` and `UnmodifiableMapView` in Basket,
* a regular (non-anonymous) class that implements the desired behaviour,
and is only used for this one property,
* or something I haven't thought of?

Thank you so much!
Best regards,
Philipp
--
For other discussions, see https://groups.google.com/a/dartlang.org/

For HOWTO questions, visit http://stackoverflow.com/tags/dart

To file a bug report or feature request, go to http://www.dartbug.com/new
---
You received this message because you are subscribed to the Google Groups "Dart Misc" group.
To unsubscribe from this group and stop receiving emails from it, send an email to misc+***@dartlang.org.
Filipe Morgado
2016-08-09 14:57:02 UTC
Permalink
Hi,

Personally, I like 'getItem', 'setItem', etc.
It's probably the most efficient and easy to implement.
It reminds me of 'addChild', 'addChildAt', 'removeChild', etc ... from AS3
display list.

However, if there are a lot of lists of maps everywhere which require some
background processing when items are added/removed, we end-up with a lot of
duplication.
So I used a custom List once:

typedef void ItemCallback<T>(T item);

class CustomList<T> implements List {
final List<T> _source;
final ItemCallback _itemAdded;
final ItemCallback _itemRemoved;

const CustomList(List<T> source, this._itemAdded, this._itemRemoved):
_source = source == null ? <T>[] : source;

void add(T item) {
_source.add(item);
_itemAdded(item);
}

void remove(T item) {
_source.remove(item);
_itemRemoved(item);
}

// Here goes complete List implementation ...
}

class Child {}
class Filter {}

class Container {
final _children = <Child>[];
CustomList _childrenList;
List get children => _childrenList;

final _filters = <Filter>[];
CustomList _filtersList;
List get filters => _filtersList;

Container() {
_childrenList = new CustomList<Child>(_children, _onChildAdded,
_onChildRemoved);
_filtersList = new CustomList<Filter>(_filters, _onFilterAdded,
_onFilterRemoved);
}

void _onChildAdded() {
// process added child
}

void _onChildRemoved() {
// process removed child
}

void _onFilterAdded() {
// process added filter
}

void _onFilterRemoved() {
// process removed filter
}
}

void main() {
final container = new Container();
container.children.add(new Child());
constainer.filters.add(new Filter());
}

The container may keep a reference to the underlying lists, so it may
efficiently cycle them.

I've used something like this in an experimental WebGL engine
<https://github.com/fmorgado/pixies> and it's the only place I've needed
something similar (in Dart).
My custom implementation is here
<https://github.com/fmorgado/pixies/blob/master/lib/src/controllers/data/list_collection.dart>,
and it's used here
<https://github.com/fmorgado/pixies/blob/master/lib/src/stage/core/renderable.dart>
, here
<https://github.com/fmorgado/pixies/blob/master/lib/src/stage/core/renderable_container.dart> and
here
<https://github.com/fmorgado/pixies/blob/master/lib/src/engine/gl_engine.dart>
.
The code is a little old and there's some cleanup to do. There are caveats
(probably shouldn't mess with the list in an 'added' callback). Not
everybody will like it.
I actually didn't implement List, which would require 10x more code and
testing. I just needed 'add', 'remove' and 'operator []'.

Others will have better solutions, but I hope this one helps.

P.S. The code above probably contains errors.
--
For other discussions, see https://groups.google.com/a/dartlang.org/

For HOWTO questions, visit http://stackoverflow.com/tags/dart

To file a bug report or feature request, go to http://www.dartbug.com/new
---
You received this message because you are subscribed to the Google Groups "Dart Misc" group.
To unsubscribe from this group and stop receiving emails from it, send an email to misc+***@dartlang.org.
tatumizer-v0.2
2016-08-09 16:45:11 UTC
Permalink
Maybe you are looking for delegating versions of list/map?
https://www.dartdocs.org/documentation/quiver/0.22.0/quiver.collection/DelegatingList-class.html
https://www.dartdocs.org/documentation/quiver/0.22.0/quiver.collection/DelegatingMap-class.html
--
For other discussions, see https://groups.google.com/a/dartlang.org/

For HOWTO questions, visit http://stackoverflow.com/tags/dart

To file a bug report or feature request, go to http://www.dartbug.com/new
---
You received this message because you are subscribed to the Google Groups "Dart Misc" group.
To unsubscribe from this group and stop receiving emails from it, send an email to misc+***@dartlang.org.
Filipe Morgado
2016-08-09 18:20:40 UTC
Permalink
True!
That's the Darty way.

I try to limit my dependencies because code size escalates quickly and the
more I import, the more unresponsive the analyzer used to get.
And we gain a few FPS in a display engine by eliminating abstractions.
Post by tatumizer-v0.2
Maybe you are looking for delegating versions of list/map?
https://www.dartdocs.org/documentation/quiver/0.22.0/quiver.collection/DelegatingList-class.html
https://www.dartdocs.org/documentation/quiver/0.22.0/quiver.collection/DelegatingMap-class.html
--
For other discussions, see https://groups.google.com/a/dartlang.org/

For HOWTO questions, visit http://stackoverflow.com/tags/dart

To file a bug report or feature request, go to http://www.dartbug.com/new
---
You received this message because you are subscribed to the Google Groups "Dart Misc" group.
To unsubscribe from this group and stop receiving emails from it, send an email to misc+***@dartlang.org.
'Lasse R.H. Nielsen' via Dart Misc
2016-08-12 10:55:11 UTC
Permalink
From a purely (my!) style point of view, I would probably never expose a
Map property directly.
You have a class representing some abstraction. Its methods should be
written in terms of that abstraction. Exposing a Map is revealing an
implementation detail (there is nothing in the "Basket" name that suggests
that baskets have mappings).

/L
Post by Filipe Morgado
True!
That's the Darty way.
I try to limit my dependencies because code size escalates quickly and the
more I import, the more unresponsive the analyzer used to get.
And we gain a few FPS in a display engine by eliminating abstractions.
Post by tatumizer-v0.2
Maybe you are looking for delegating versions of list/map?
https://www.dartdocs.org/documentation/quiver/0.22.0/quiver.
collection/DelegatingList-class.html
https://www.dartdocs.org/documentation/quiver/0.22.0/quiver.
collection/DelegatingMap-class.html
--
For other discussions, see https://groups.google.com/a/dartlang.org/
For HOWTO questions, visit http://stackoverflow.com/tags/dart
To file a bug report or feature request, go to http://www.dartbug.com/new
---
You received this message because you are subscribed to the Google Groups
"Dart Misc" group.
To unsubscribe from this group and stop receiving emails from it, send an
--
Lasse R.H. Nielsen - ***@google.com
'Faith without judgement merely degrades the spirit divine'
Google Denmark ApS - Frederiksborggade 20B, 1 sal - 1360 KÞbenhavn K
- Denmark - CVR nr. 28 86 69 84
--
For other discussions, see https://groups.google.com/a/dartlang.org/

For HOWTO questions, visit http://stackoverflow.com/tags/dart

To file a bug report or feature request, go to http://www.dartbug.com/new
---
You received this message because you are subscribed to the Google Groups "Dart Misc" group.
To unsubscribe from this group and stop receiving emails from it, send an email to misc+***@dartlang.org.
Philipp S
2016-08-17 16:51:37 UTC
Permalink
Hey!
Thanks for your answers, and please excuse the delay on my side :(

Maybe you are looking for delegating versions of list/map?

Thanks for the hint, I didn't know about that package at all, it looks
promising!

From a purely (my!) style point of view, I would probably never expose a
Map property directly. [...] there is nothing in the "Basket" name that
suggests that baskets have mappings
Would've been better to come up with an appropriate example earlier, but I
could think of one only now: `HtmlElement.attributes`[1] from dart:html and
`ClassMirror.declarations`[2] from dart:mirrors both expose properties of
type Map, with custom behavior tied to them.
What I'd prefer is such a customized map, but with as little code overhead
as possible. I'll probably try around with extending DelegatingMap, and
adding explicit getters and setters to the parent class, in the next days,
and report back if I stumble upon a solution that really satisfies me :)

Best regards
Philipp

[1]: https://api.dartlang.org/stable/1.18.1/dart-html/Element/attributes.html
[2]: https://api.dartlang.org/stable/1.18.1/dart-mirrors/ClassMirror/declarations.html
--
For other discussions, see https://groups.google.com/a/dartlang.org/

For HOWTO questions, visit http://stackoverflow.com/tags/dart

To file a bug report or feature request, go to http://www.dartbug.com/new
---
You received this message because you are subscribed to the Google Groups "Dart Misc" group.
To unsubscribe from this group and stop receiving emails from it, send an email to misc+***@dartlang.org.
Loading...