Regardless of how obvious the programming language makes it, when we program, we are surrounded by objects. Tons of intricate objects. For example, in my current development Pharo image I have 4’640’935 instances of classes.
To tame these objects, we need to understand their inner structure and their inter-relationships. How do we best do that? By means of browsers. A browser is a specific user interface that allows us to look at the object space, to navigate from one part of this space to another, and to act upon it.
Browsers can be of many kinds, but for the purpose of this discussion we will distinguish between generic and dedicated ones.
In Smalltalk, for example, the central browser is the Inspector. This is a generic tool that allows us to manipulate objects from the point of view of the Smalltalk language. It accommodates any instance of any class, it shows us the inner structure of the instance in terms of its variables, and it allows us to execute code that takes involves the current instance.
This is a great tool, but it is not effective when it comes to navigating a set of objects from the point of view of a model that is at a higher level and that ignores the internal implementation details. Because the Inspector offers a low level point of view on the objects, whenever we want to discover a higher level structure we are required to go through many irrelevant, implementation-related, clicks to get to the objects of interest.
A better way is to use a browser that supports a flow dedicated to the model of interest. For example, when it comes to manipulating code, we use a code browser. In Smalltalk, we could write code in the Inspector, but we typically prefer not to.
Dedicated browsers are desirable, but they are expensive to build. As a result we have no dedicated way to browse the large majority of objects around us. This situation needs rectification. This is why, a year ago we (Philipp Bunge, me, Lukas Renggli, Jorge Ressia and David Röthlisberger) started to build Glamour, an engine for building dedicated browsers.
How exactly does Glamour help us build dedicated browsers? The rest of the post tries to answer this question through a hands-on example.
First, let’s see in more details what a browser is made of. As a case study, let’s take a classic code browser like the one from the figure below.
We get four panes: three at the top and one below. The top-left pane holds the namespaces (or packages) from the system presented as a list or as a tree. Once a package is selected, its classes are shown as a list on the top-center pane. In the same way, the methods of a selected class are shown on the top-right pane. The pane at the bottom shows the source code of a selected method. The essence of the browser is shown schematically below.
We get five main concepts. A browser (1) is made of panes (2) which represent spatial locations on which various objects (3) are presented (4). Furthermore, the result of acting on the graphical presentation (4) is transmitted (5) to other panes.
It is actually quite simple. Let’s see how we can express this browser using the Pharo version of Glamour. If you are not fluent in Smalltalk, reading the code as regular text will help. The example is based on using a code model provided by the Moose analysis platform.
We first create the browser:
| browser |
browser := GLMTabulator new.
The browser is composed by four panes which we will call: #namespaces
, #classes
, #methods
and #details
. These panes are arranged in two rows, where the top one is further composed by three columns:
browser
row: [ :r | r column: #namespaces; column: #classes; column: #methods ];
row: #details.
Given an input Moose model, we want to show the namespaces objects from the model on the #namespaces
pane. These namespaces are presented as a tree. We start from the root namespaces, and then we show all children. The frame of the specification is given by Glamour (e.g., showOn:
or tree
), while for the actual details of programatically navigating the code we use methods offered by the data model (e.g., allNamespaces
, isRoot
or childScopes
).
browser transmit to: #namespaces; andShow: [ :a |
a tree
display: [ :model | model allNamespaces select: [ :each | each isRoot ] ];
children: [ :namespace | namespace childScopes ];
format: [ :namespace | namespace stubFormattedName ] ].
Once we select a namespace, we want to transmit to the #classes
pane that it should display a list with all the classes from the namespace:
browser transmit to: #classes; from: #namespaces; andShow: [ :a |
a list
display: [ :namespace | namespace classes ];
format: [ :class | class stubFormattedName ] ].
In a similar way, we want to show the methods of a class:
browser transmit to: #methods; from: #classes; andShow: [ :a |
a list
display: [ :class | class methods ];
format: [ :method | method stubFormattedName ] ].
We want the source code for a selected method to be shown in the #details
pane:
browser transmit to: #details; from: #methods; andShow: [ :a |
a text
display: [ :method | method sourceText ] ].
Finally, we start the browser by providing a MooseModel:
browser openOn: MooseModel root allModels anyOne.
That’s it. The result of running the above code is seen below.
This was a glimpse of Glamour. There are certainly more things to talk about, but the essence is that once you know how to navigate programatically through your model, the creation of a browser becomes rather straightforward.
If you want to learn more about Glamour (and Moose) I encourage you to send us an email via the moose-dev@iam.unibe.ch mailing list.
Comments
te mai citeam din cand in cand, dar cu asta m-ai pierdut pe undeva pe drum :)
ce as putea eu sa zic in aceste conditii ... :)