[squeak-dev] Re: [ANN] Preference pragmas
Alain Plantec
alain.plantec at univ-brest.fr
Fri Mar 6 09:30:03 UTC 2009
Hi Andreas,
Andreas Raab a écrit :
> Alain's implementation of preferences is an improvement on the current
> preference system but it is effectively replacing one set of
> dependencies with a different set of dependencies. Where previously
> Preferences would be registered and stored via Preferences
> addPreference:... in Alain's approach preferences get created via (the
> old version):
...
> or, with the latest:
>
> gradientButtonLook
> <preference>
> ^ GradientButtonLook
> ifNil: [GradientButtonLook := PreferenceValue
> name: 'Gradient look for buttons'
> description: 'Gradient look for buttons'
> parent: #uiPreferenceNode
> type: #Boolean
> default: false]
>
> In other words, a dependency (to either PreferenceNode,
> PreferenceValue, RangePreferenceValue, MultiplePreferenceValue etc) is
> created and stored client-side.
With Pharo approach, your code depends on a unique small hierarchy of
classes exactly as it can depend on Collection one.
It does not depend on a global object (Preferences) as it is now.
For me, it is not a problem since preferences are declared locally in
packages (exactly as in your pragma approach)
>
> My approach differs in such that it is aimed at being discoverable
> without introducing any dependencies.
I don't think so, you are introducing a dependency on a particular
syntax wich is <preference: something: somethingelse: >
I think it is better to rely on classes and not to depend on a flat syntax.
> defaultPollPeriod
> "Answer the number of milliseconds between interrupts for spyOn:
> and friends.
> This should be faster for faster machines."
> <preference: 'Default Poll Period'
> category: 'Profiling'
> description: 'The default poll period (msecs) MessageTally uses'
> type: #Number>
> ^DefaultPollPeriod ifNil: [ DefaultPollPeriod _ 1 ]
>
You also need
defaultPollPeriod: aNumber
DefaultPollPeriod := aNumber
and maybe another method for the default and maybe something else for
system level notification.
Only a detail maybe but In our implementation, for one preference, you
need to set only one declaration:
and you use the preference like this:
v := UIPreferences gradientButtonLook value.
UIPreferences gradientButtonLook value: false.
It allows system level notification because #PreferenceValue>>value:
triggers a #PreferenceChanged events.
An object can be declared as listener to a particular preference value
like this:
MyObject>>initialize
super initialize.
UIPreferences gradientButtonLook whenChangedSend:
#gradientButtonLookIsNow: to: self.
the opposite is #forget:
MyObject>>release
UIPreferences gradientButtonLook forget: self
You can see it as a replacement for changeInformee: informeeSymbol
changeSelector: aChangeSelector.
> However, since this was discovered via pragmas, no dependency between
> Preferences and MessageTally has been created.
again, the dependency is on the syntax of the pragma
> You can remove or replace the preferences implementation in the image
> without any side effects whatsoever on MessageTally or its code. A
> different preference implementation can discover the same preference
> and present it accordingly. This allows adding preferences wherever is
> convenient without needlessly introducing dependencies on a particular
> preference implementation or UI.
Pharo preference do not depends on a particular UI. PreferenceSupport is
removeable without any side effect on the system.
But I agree that it depends on the PreferenceNode hierarchy.
>
>
> In Alain's version this would not be possible without actually
> changing code since it is directly coupled to a particular preference
> class and API.
ok but the pragma-only declaration is poor: only flat syntax which
allows only literals as parameters.
the consequence is that you can't deal with one-to-many or range
preference or something else you can discover later.
Two examples:
here the value domain is explicitly given with the help of a
MultiplePreferenceValue. Each possible value of the preference is given
with FixedPreferenceValue instances.
themePreference
<preference>
^ ThemePreference
ifNil: [ThemePreference := MultiplePreferenceValue
name: 'UITheme'
description: 'The theme to use for UI look and feel'
parent: #uiPreferenceNode
type: #UITheme
default: UIThemeWatery2
values: {
FixedPreferenceValue
name: 'Standard Squeak'
description: 'Standard Squeak style'
type: #UITheme
value: UIThemeStandardSqueak.
FixedPreferenceValue
name: 'Watery 2'
description: 'Similar to a nice OS'
type: #UITheme
value: UIThemeWatery2}]
here a range preference value, again, the value domain is explicitly given.
glyphContrast
<preference>
^ GlyphContrast
ifNil: [GlyphContrast := RangePreferenceValue
name: 'Glyph contrast'
description: 'Change the contrast level for
glyphs. This is an integer between 1 and 100. (the default value is 50)'
parent: #freeTypePreferenceNode
type: #Integer
default: 50
range: (1 to: 100)]
If you only make use of a poor preference declaration (I consider
preference pragma flat declaration as a poor flat textual declaration)
it can have bad effects on the quality of the code which is using
the preference.
See how freetype hinting preference are currently handled.
You have 4 boolean preferences wheras following declaration better fits:
hintingPreference
<preference>
^ HintingPreference
ifNil: [HintingPreference := MultiplePreferenceValue
name: 'Hinting'
description: 'Changes the glyph shapes'
parent: #freeTypePreferenceNode
type: #Symbol
default: #Light
values: {
FixedPreferenceValue
name: 'Light'
description: 'Light hinting, bla bla bla
....'
type: #Symbol
value: #Light.
FixedPreferenceValue
name: 'Full'
description: 'Full hinting bla bla bla ....'
type: #Symbol
value: #Full.
FixedPreferenceValue
name: 'None'
description: 'None hinting bla bla bla ....'
type: #Symbol
value: #None.
FixedPreferenceValue
name: 'Normal'
description: 'Normal hinting bla bla bla
....'
type: #Symbol
value: #Normal}]
FixedPreferenceValue instance can be also bound to more complex values
than simple symbol (#Light, #Full ...)
FixedPreferenceValue
name: 'Light'
description: 'Light hinting, bla bla bla
....'
type: #FreeTypeHinting
value: [FreeTypeLightHinting new].
or
FixedPreferenceValue
name: 'Light'
description: 'Light hinting, bla bla bla
....'
type: #FreeTypeHinting
value: (MessageSend receiver:
FreeTypeLightHinting selector: #new).
Thus, the declaration is more rich. As a consequence, also with the help
of the system level notification,
a client code can be much more simple and well designed.
I mean avoiding code like:
FreeTypeSettings>>hintingFullPreferenceChanged
Preferences HintingFull
ifTrue:[Preferences disable: #HintingNone; disable:
#HintingLight; disable: #HintingNormal]
ifFalse:[
(Preferences HintingNone or:[Preferences HintingLight
or:[Preferences HintingNormal]])
ifFalse:[
"turn it back on again"
^Preferences enable: #HintingFull]].
monoHinting := Preferences HintingFull.
lightHinting := Preferences HintingLight.
hinting := monoHinting or:[lightHinting or:[Preferences HintingNormal]].
FreeTypeCache current removeAll.
FreeTypeFont allSubInstances do:[:each | each clearCachedMetrics].
NewParagraph allSubInstances do:[:each | each composeAll].
World restoreMorphicDisplay.
The last point you maybe missed (which is maybe not so important) is
that what we are declaring is a tree of preferences.
See Snapshot attached (For now, only a poor tool version,
"PreferenceTree open" to see it in action), it ilustrates well the point.
An again, this kind of tool is NOT mandatory. Related package can be
removed without side effect on the system because
it also makes use of dynamic preference discovering with the help of Pragma.
ah, the real last point is the default value: in your point of view,
default values depend on value type.
I can't agree with that point of view. It would mean, as an example,
that every boolean preferences have false, or true as the default.
The problem with non-literals then arises if you want to declare default
value with pragma...
ah, again. If your system relies on a <preference:truc:...> syntax. What
about evolution of the system ?
If you want to change all declarations, you have to find them all. As
far as I know, you can't rely on standard code browser for it.
And what about external tools and user application ?
Gary Chambers quote: -------------------------
> The simple pragma approach I described would make it easier for the
> tools though since they wouldn't need a separate model (or hang onto
> the pragma) in order to work.
>
> Also, for user applications. Our ReportBuilder, for instance, also has
> an end-user ui for preferences local to itself. Having acccess to the
> default value/description withough having to find the pragma would be
> easier. (Just an example, the ReportBuilder actually uses xml config
> files for its prefs).
------------------------- End of Gary quote
>
> Bottom line: I think my approach is a necessity before Alain's
> preference implementation can be usefully deployed. It allows us to
> define preferences without introducing dependencies to specific
> implementations, while allowing different implementations to discover
> the same preferences.
I do not really understand.
>
> I hope this makes the conceptual difference clear.
Thanks for it.
...and remarks, critics, idea, improvements are welcomed.
Cheers
alain
>
> Cheers,
> - Andreas
>
>
>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: Preference tree.png
Type: image/png
Size: 43018 bytes
Desc: not available
Url : http://lists.squeakfoundation.org/pipermail/squeak-dev/attachments/20090306/e5bf0bfc/Preferencetree.png
More information about the Squeak-dev
mailing list
|