[squeak-dev] Re: [ANN] Preference pragmas

Alain Plantec alain.plantec at univ-brest.fr
Fri Mar 6 22:18:34 UTC 2009


Andreas Raab a écrit :
> Hi Alain -
>
>
> The sole purposes of preferences is to expose certain system variables 
> to the end-user. Consequently, preferences are part of the UI layer.
It a point of view which I can agree on, but what now ?
>>> 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.
ok but your tools which discover the preferences depends on the syntax.
>
> 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.
ok
>
>>> 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
> 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.
MessageTally>>defaultPollPeriod
    <preference>
    ^ DefaultPollPeriod ifNil: [ DefaultPollPeriod :=
            PreferenceValue
                        name: 'Default Poll Period'
                        description: 'The default poll period (msecs) 
MessageTally uses'
                        parent: #httpProxyPreferenceNode
                        type: #Number
                        default: 1]
>
>> 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).
I can also use Announcement. In fact, this part is hidden, it is 
encapsulated by PreferenceValue>>value:
the developper does not have to deal with it. From my point of view, 
this is a good thing.
PreferenceValue>>valueSilently: can also be used if the announce is useless.
>
> 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.
maybe "dependency on syntax" is not the good way to say that but you 
have to deal with several pragma syntaxes, at least from discovering 
tools point of view.
>
>> 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
again another way of using pragmas (yet another syntax). I really prefer 
objects and messages.
>
> 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)
with the risk that a pragma form or syntax is not used or recognized 
anymore and so completely useless.
>
> 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.
This is also the solution I used when I was trying an implementation 
like yours, I mean with <preference:xxx:yyyy:...>
>
>> 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"
>     ].
>     "..."
ok but again #(light medium heavy) is low level.
maybe the programmer wants the preference value to be a complex object 
on which a strategy pattern can rely on as an example.
If you use symbols, the strategy can not be directly used, then the code 
is more complex

>
>> 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 use of symbols implies the use of alternatives. From my point of 
view, it can be a bad practice:
v = #light ifTrue: [ ... ]
v = #medium ifTrue: [...]
v = #heavy ifTrue: [...]
can reveal a bad design (I don't say it is always bad)
>
>> 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.
at least UI code need default values.
^DefaultPollPeriod ifNil: [ DefaultPollPeriod := 1 ]
here, 1 represents a start value.
suppose a user changes this to 3 and suppose that later he wants to come 
back to the start value.
in that case the default is useful.
>
> [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.
I think it is not desirable to have something useless in code.
If I understand well, you say that methods can contain 
<preference:glorp:> and that is
doesn't matter is the system doesn't know how to handle or use it,
and if it is usable or not. Even the code continues to work, I would not 
like it.
>
>> 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.
What I mean is that there is no way to query methods which contain 
pragma from regular browsers.
You have to write the tool with Pragma class.
With pharo solution, withsimply the help of regular Browser, you can 
query all senders of #name:description:parent:type:default: in order
to get all PreferenceValue users and then to get preference methods.
>
>> 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 ;-)
yes, ok, it was only an example and it is a small quote.
>
> 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.*
I've almost done it myself as a first implementation (with 
<preference:xxx:yyy:> pragma).
The link with current PreferenceBrowser was not done but I had a 
PreferenceCollector which was collecting all preferences.
>
>
> 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. 
yes
> 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. 
oups ! sorry
> Can you point me to some code that I can actually load and play with?
ok, I will send the packages with some explanations.

Thanks
alain

> Thanks.
>
> Cheers,
>   - Andreas
>
>




More information about the Squeak-dev mailing list