I have been using Observatory for trying to understand the program heap and finding devtools lacks some equivalent general abilities.
The two key features are:
- Evaluation of an expression in any context.
- Making heap queries available as Dart runtime values.
I want to be able to 'move' around the memory graph.
I want to be able to select some object and then be there.
In observatory I can shift-click on an object and get a new tab which is 'at' the object.
Expressions are evaluated with this bound to the object, e.g. in a _List, the expression length will give the length of the list.
In standard debugging I can single-step to a location and see the values stored in variables in scope, but I want that power without first running the program to some point.
Disconnecting a REPL from the control flow of the application is the fundamental feature here.
There might be an alternative to having many 'object inspector' tabs that are 'at' different objects.
Perhaps the inspected value could be copied to the console's value history and be used from there.
The value history could be made available by injected variable names.
Instead of the console showing
it would name all the values
> 123
$21: 123
> $21 + 100
$22: 223
>
Clicking on some node in some other view might then add it to the history
$23: { ⊞ } // another clickable expandable reference to the object that was under the pointer
I can now use it in an expression:
I think it would be helpful for this approach to be able to expand values in the console to 'grab' sub-elements, but currently I see unhelpful text like Instance of 'CompilerOptions'.
I want to be able to get a list of all instances of a class
It is very powerful to be able to programatically inspect all instances of a class. You can do things like ask how many strings contain "hello"
this.where((s) => s.contains('hello')).length
The this. would normally be implicit.
I have been asking questions that would normally require modifying the program.
- How many tree nodes have a specific kind of parent node?
- Get a random sample of ten elements:
(this..shuffle()).sublist(0, 10)
- Group by length (or some other attribute):
fold({}, (Map m, s) {(m[s.length]??=[]).add(s); return m;})
There are three levels of the 'all instances' feature, and all are useful:
- All instances of a class ('all')
- All instances of a class and its subclasses ('all + extends')
- All instances of a class and its subtypes ('all + implements')
In Observatory, I often get to this place from an allocation profile.
- Look at the allocation profile.
- Click on a class.
- Click on the ↺ to fetch the list of instances
- Click on the instance of
_List returned for the instances
- Evaluate the query, e.g.
where((s) => s.contains("hello")).length.
Inbound references to a object
I use inbound references a lot in understanding why a value has not been GC-ed.
It might be useful for this to be surfaced as an object that can be used programmatically.
Even if it is not that useful, a reified set of references can be inspected as any other object rather than via a special UI.
I have been using Observatory for trying to understand the program heap and finding devtools lacks some equivalent general abilities.
The two key features are:
I want to be able to 'move' around the memory graph.
I want to be able to select some object and then be there.
In observatory I can shift-click on an object and get a new tab which is 'at' the object.
Expressions are evaluated with
thisbound to the object, e.g. in a_List, the expressionlengthwill give the length of the list.In standard debugging I can single-step to a location and see the values stored in variables in scope, but I want that power without first running the program to some point.
Disconnecting a REPL from the control flow of the application is the fundamental feature here.
There might be an alternative to having many 'object inspector' tabs that are 'at' different objects.
Perhaps the inspected value could be copied to the console's value history and be used from there.
The value history could be made available by injected variable names.
Instead of the console showing
it would name all the values
Clicking on some node in some other view might then add it to the history
I can now use it in an expression:
I think it would be helpful for this approach to be able to expand values in the console to 'grab' sub-elements, but currently I see unhelpful text like
Instance of 'CompilerOptions'.I want to be able to get a list of all instances of a class
It is very powerful to be able to programatically inspect all instances of a class. You can do things like ask how many strings contain
"hello"The
this.would normally be implicit.I have been asking questions that would normally require modifying the program.
(this..shuffle()).sublist(0, 10)fold({}, (Map m, s) {(m[s.length]??=[]).add(s); return m;})There are three levels of the 'all instances' feature, and all are useful:
In Observatory, I often get to this place from an allocation profile.
_Listreturned for the instanceswhere((s) => s.contains("hello")).length.Inbound references to a object
I use inbound references a lot in understanding why a value has not been GC-ed.
It might be useful for this to be surfaced as an object that can be used programmatically.
Even if it is not that useful, a reified set of references can be inspected as any other object rather than via a special UI.