[squeak-dev] Preferences revamp redux

Eliot Miranda eliot.miranda at gmail.com
Mon Dec 19 21:33:16 UTC 2016

Hi All,

   from Chris's requirement #4,  4) Ability to ask any Preference its
default value, without resetting its current value, here's some simple code
for extracting the default value from a pragma preference method, if it
specifies a literal default value.

The three styles of providing defaults in pragma preferences are essentially

    ^ClassVar ifNil: [#someDefaultLiteral]

    ^ClassVar ifNil: [ClassVar := #someDefaultLiteral]

    anything else (and we'll see all of these soon).

Looking at the byte codes for the first two forms we see

21 <40> pushLit: ThoroughSenders
22 <88> dup
23 <73> pushConstant: nil
24 <C6> send: ==
25 <99> jumpFalse: 28
26 <87> pop
27 <71> pushConstant: true
28 <7C> returnTop

21 <40> pushLit: ShowSugarNavigator
22 <88> dup
23 <73> pushConstant: nil
24 <C6> send: ==
25 <9B> jumpFalse: 30
26 <87> pop
27 <72> pushConstant: false
28 <81 C0> storeIntoLit: ShowSugarNavigator
30 <7C> returnTop

CompiledMethod provides abstractBytecodeMessagesDo: to enumerate over the
byte codes independently of the byte code set's encoding.  So this extracts
the default value from one of the two above:

| literal |
self abstractBytecodeMessagesDo:
msg selector == #pushConstant:
ifTrue: [literal := msg argument]
[msg selector == #methodReturnTop ifTrue: [^literal].
msg selector ~~ #storeIntoLiteralVariable: ifTrue:
[literal := nil]]].

It works by identifying any literal via "msg selector == #pushConstant:"
and stores it in literal.  Then if it sees anything other than
#methodReturnTop or #storeIntoLiteralVariable: it nils the literal.  And it
returns the value of literal as soon as it sees #methodReturnTop.

So the following browses all the pragma preferences in the system that
don't fit the first two pattens:

self systemNavigation browseAllSelect:
(m pragmaAt: #preference:category:description:type:) notNil
and: [| literal |
m abstractBytecodeMessagesDo:
msg selector == #pushConstant:
ifTrue: [literal := msg argument]
[(msg selector ~~ #methodReturnTop
 and: [msg selector ~~ #storeIntoLiteralVariable:]) ifTrue:
[literal := nil]]].
literal isNil]]

Of 121 pragma preference methods in my system 22 don't fit the pattern.
Some are project-specific preferences that defer to Project's own custom
preference framework, which is necessary to allow individual projects to
have their individual preferences (something that the dictionary of
preferences framework also cannot handle without special accommodation).
Some are bad examples:

<preference: 'Boolean Preference Example'
category: 'Examples'
description: 'A simple example for a boolean preference  (see
type: #Boolean>

Some are richer:
<preference: 'Corner Grip highlight color'
category: 'colors'
description: 'The highlight-color of window corners'
type: #Color>
^(self activeForm colorAt: 24 at 24) alpha:  1

But I hope you get the point that with very little machinery we can extract
the default value in a substantial majority of cases.

Since we'd also like to get rid of the setter it would be good to be able
to extract the class variable so it can be set simply by sending it #value:
, so... allow me to add abstractBytecodeMessages, then something similar to
the following (*)

(((method abstractBytecodeMessages first: 5) collect: [:ea| ea selector])
hasEqualElements: #(#pushLiteralVariable: #doDup #pushConstant:
#send:super:numArgs: #jump:if:)) ifTrue:
[^(method abstractBytecodeMessageAt: method initialPC) argument]

answers the class variable, allowing the Preference UI to
- derive its current value
- reset its value given the default extracted above

(*) one could insist on the send being of #== and the pushConstant:
supplying nil.

So with these two pieces of machinery in the Preferences UI we don't need
setter methods for pragma preferences at all. Note that none of the
bytecode magic has to be visible to the author of a pragma preference, but
i does have to be understood by the maintainer of the Preference UI.

best, Eliot
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.squeakfoundation.org/pipermail/squeak-dev/attachments/20161219/b0c2c095/attachment.html>

More information about the Squeak-dev mailing list