[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