[squeak-dev] Re: [ANN] Preference pragmas
Andreas Raab
andreas.raab at gmx.de
Fri Mar 6 17:20:01 UTC 2009
Hi Alain -
Alain Plantec wrote:
> With Pharo approach, your code depends on a unique small hierarchy of
> classes exactly as it can depend on Collection one.
To me there is a big difference: From my perspective all preferences
code is UI code. Why? Because at the system level we use class variables
and messages, not preferences. At the system level if you want to
broadcast an event you use announcements or some other event system.
The sole purposes of preferences is to expose certain system variables
to the end-user. Consequently, preferences are part of the UI layer.
> 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)
Yes, we agree on that.
>> 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.
There is no dependency on syntax. A dependency exists if some code
requires some other code to be present in order to function correctly.
In other words, if you load code that uses your preferences into some
other image it will not function until your preference implementation is
loaded. That is a dependency.
With preference pragmas as I have proposed them, the code can be loaded
into any image that supports pragmas. Put differently, I can load that
MessageTally class into Pharo, and it will continue to function
precisely the same. There is no dependency other than pragmas.
>> 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
The point here is that these methods exist already. What I demonstrated
in the above is that you can decide after the fact that you'd like to
expose a variable from your code to the end-user simply by putting a
preference pragma into it. With your implementation this would requires
rewriting several methods with mine it is simply marking up the method
to be discovered by preferences.
Actually, do me a favour and make a change that exposes
defaultPollPeriod via your implementation. This will allow us to compare
notes and also put the dependency discussion into context.
> It allows system level notification because #PreferenceValue>>value:
> triggers a #PreferenceChanged events.
Obviously, if you'd like notifications about something like it you would
use, e.g.,
MessageTally class>>defaultPollPeriod: aNumber
DefaultPollPeriod := aNumber.
self announce: (DefaultPollPeriodChanged value: aNumber).
so it's simply a regular event that notifies listeners about the change
if that is desired (and of course, if you'd want to present this as a
preference event you could do that too).
>> 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
There is no dependency on syntax. The FFI has a dependency on syntax as
in ulong 'SomeMethod' (ulong long char*) etc. Tweak has a dependency on
syntax, such as remote assignments as in anObject value := 42.
Preference pragmas have no dependency on syntax. Preference pragmas mark
up methods so that they can be discovered by a preference implementation.
> 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.
See above. To me it's all UI code.
> 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.
Ah, but you can. That is a major advantage of it. For example, consider
range:
glyphContrast
<preference: 'Glyph contrast'
category: 'Freetype'
description: 'Change the contrast level for glyphs. This is an integer
between 1 and 100. (the default value is 50)'
type: #Number
min: 1
max: 100>
^GlyphContrast
Now, what is going to happen? A preference implementation will ignore
any preference pattern that it doesn't recognize. The code will still
continue to function, the preferences implementation will simply not be
able to make sense of the markup but nothing will get broken. So you get
even forward compatibility for free! (if the preference implementation
is smart it might be able to display this as grayed out to help people
giving feedback that there is something odd about it)
You can invent more complex patterns, custom patterns that only your
preference browser supports. Without breaking anyones code, without
introducing dependencies.
> 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.
Simplicity rules. At the point where you start wanting to have complex
UIs for setting preferences, I would offer the option to embed such UIs
directly, along the lines of:
uiTheme
<preference: 'UI Theme'
panelMorph: #uiThemeChooserMorph
description: 'The UI Theme'>
The panelMorph would describe a selector that is called by the
preference implementation to provide a custom preference panel. This
allows for maximum flexibility without the need to complicate the
implementation.
However, this just emphasizes that all of this is UI code. All you do is
providing instructions for the UI how to present things. Nothing wrong
with it, but goes to the heart of why I think all of this is really UI code.
> 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.
How so? The preference isn't even visible to code. Code only uses what
code has ever used: Variables and Messages.
> See how freetype hinting preference are currently handled.
> You have 4 boolean preferences wheras following declaration better fits:
Okay. How about this:
hintingPreference
<preference: 'Hinting Preference'
category: 'FreeType'
description: 'How glyphs should be rendered'
type: #Choice
values: #(light medium heavy)>
^HintingPreference
hintingPreference: aSymbol
aSymbol = #light ifTrue:[
"set light hinting values"
].
"..."
> 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'm not sure why your example would be simpler or better designed than
what I am showing above. I mean my point here is that you provide the
methods that are being required, that you actually write the code that
other client code would use. And once you've done this you just tell the
system that it also can present that as a preference.
> The last point you maybe missed (which is maybe not so important) is
> that what we are declaring is a tree of preferences.
Yes. But again, extensibility is a major advantage of pragma
preferences. See above.
> ah, the real last point is the default value: in your point of view,
> default values depend on value type.
No! Absolutely not. From my point of view there is no "default" value
(well, you could add this if you needed it but I think it's completely
pointless). There is only the current value which is the value of some
variable.
[I will admit that my implementation is incomplete in this regard; it
should not use the Preference's value but rather fetch the value
straight from the source. I'll fix that eventually]
> 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...
Once more, there is no "default". If one needed it it could be added
(cf. extensibility above) but I don't see a need. A preference is some
variable that has a value, no more.
> ah, again. If your system relies on a <preference:truc:...> syntax. What
> about evolution of the system ?
And for a third time, there is no dependency, so there is no issue with
evolution of the system. If you load code that has a preference pragma
into a system that doesn't know what to do with it, it will just ignore
it. Your code will continue to function without any modifications.
> 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 ?
I don't understand that. You can browse pragmas like regular messages,
you can edit them in regular browsers. There is no issue that I am aware
about.
> 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
That seems to be a very specific implementation request. I wouldn't base
a framework decision on some report builder using xml config files for
prefs ;-)
But besides that, you probably haven't looked at my code, no? ;-) I can
tell because if you had, you would have seen that what the discovery
does, is taking the preference pragma and translate it into the current
preferences system.
In other words, there is no hanging on to pragmas. Your preferences
implementation could be *easily* made to pick up the preference pragmas
that I am proposing. This is my point after all, having the ability to
replace preference implementations!
Finally, the code that I got was incomplete. At least one class
(AbstractPreferenceValue) was missing. Can you point me to some code
that I can actually load and play with? Thanks.
Cheers,
- Andreas
More information about the Squeak-dev
mailing list
|