[squeak-dev] [ANN] Preference pragmas

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
43 messages Options
123
Reply | Threaded
Open this post in threaded view
|

[squeak-dev] [ANN] Preference pragmas

Andreas.Raab
Folks -

I wanted to make the property whether to show individual processes in
MessageTally a preference and couldn't recall any of the three gazillion
methods to create one ;-) So I decided enough is enough and added the
ability to register a preference via Pragma. In other words, you specify
two class side accessors (using MessageTally as example):

showProcesses
        "Indicates whether to show each process separately or cumulatively."
        <preference: 'Show Processes in MessageTally'
                category: 'debug'
                balloonHelp: 'If enabled, each profiled process is shown individually
in MessageTally'
                type: #Boolean>
        ^ShowProcesses

showProcesses: aBool
        "Indicates whether to show each process separately or cumulatively."
        ShowProcesses := aBool.

and then register the preference in the class initialization method via:

initialize
        "MessageTally initialize"
        "By default, show each process separately"
        ShowProcesses := true.
        "Register preferences"
        Preferences addPreferencesFor: self.

The nice thing about this scheme is that the preference is local to the
code where it's used and that there are no more generated accessors
which mess up Monticello packages etc. What could probably be improved
is the self-registration; I left it that way for now since I don't know
how expensive it would be to scan all classes for new preferences when
one opens a preference browser. There is also an example class
PreferenceExample that illustrates the different types of preferences
(textual, numeric, color, boolean) you can use.

To install, just execute the following from Squeak 3.10.2:

    Installer mantis fixBug: 7306.

Enjoy!
   - Andreas

Reply | Threaded
Open this post in threaded view
|

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

Eliot Miranda-2


On Tue, Mar 3, 2009 at 11:03 PM, Andreas Raab <[hidden email]> wrote:
Folks -

I wanted to make the property whether to show individual processes in MessageTally a preference and couldn't recall any of the three gazillion methods to create one ;-) So I decided enough is enough and added the ability to register a preference via Pragma. In other words, you specify two class side accessors (using MessageTally as example):

Great to see you drinking the kool aid :)  This is cool.  Somehow "all" (many) preferences ought to be defined this way. 


Reply | Threaded
Open this post in threaded view
|

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

Michael Rueger-6
In reply to this post by Andreas.Raab
Andreas Raab wrote:

> Folks -
>
> I wanted to make the property whether to show individual processes in
> MessageTally a preference and couldn't recall any of the three gazillion
> methods to create one ;-) So I decided enough is enough and added the
> ability to register a preference via Pragma. In other words, you specify
> two class side accessors (using MessageTally as example):
>
> showProcesses
>     "Indicates whether to show each process separately or cumulatively."
>     <preference: 'Show Processes in MessageTally'
>         category: 'debug'
>         balloonHelp: 'If enabled, each profiled process is shown
> individually in MessageTally'
>         type: #Boolean>
>     ^ShowProcesses

Looking at your version I see you made some slightly different design
choices than in the design that has been in design discussion and worked
on in the last couple of weeks on the Pharo list.

Can you elaborate what motivated the different design? Meaning what
parts of the Pharo version could be made better? Or, sorry for basically
asking the same thing three times, what would it take to adopt the Pharo
version for Squeak?

Michael

Reply | Threaded
Open this post in threaded view
|

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

Bert Freudenberg
On 05.03.2009, at 00:34, Michael Rueger wrote:

> Andreas Raab wrote:
>> Folks -
>> I wanted to make the property whether to show individual processes  
>> in MessageTally a preference and couldn't recall any of the three  
>> gazillion methods to create one ;-) So I decided enough is enough  
>> and added the ability to register a preference via Pragma. In other  
>> words, you specify two class side accessors (using MessageTally as  
>> example):
>> showProcesses
>>    "Indicates whether to show each process separately or  
>> cumulatively."
>>    <preference: 'Show Processes in MessageTally'
>>        category: 'debug'
>>        balloonHelp: 'If enabled, each profiled process is shown  
>> individually in MessageTally'
>>        type: #Boolean>
>>    ^ShowProcesses
>
> Looking at your version I see you made some slightly different  
> design choices than in the design that has been in design discussion  
> and worked on in the last couple of weeks on the Pharo list.
>
> Can you elaborate what motivated the different design? Meaning what  
> parts of the Pharo version could be made better? Or, sorry for  
> basically asking the same thing three times, what would it take to  
> adopt the Pharo version for Squeak?


Hmm, at least I am not aware of what is going on in Pharoland. I'm  
reluctant to subscribe to the Pharo list. Not because I'm not  
interested, but because for one my spare time is already filled up by  
Etoys+Squeak+OLPC+Sugar, and also because the Pharo creators went to  
their own playground specifically to get away from certain opinions on  
squeak-dev. I feel like I shouldn't haunt them uninvitedly.

I wonder if someone could summarize what's going on on the greener  
side, like the weekly excerpts we sometimes get for squeak-dev ... or  
is there such a thing for Pharo already?

Anyway, I think it's great you point out this existing design.  
Duplication of effort is not something we should put up with in our  
small community. Do you have a direct pointer to the code in question?

- Bert -



Reply | Threaded
Open this post in threaded view
|

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

keith1y
In reply to this post by Michael Rueger-6
Michael Rueger wrote:

> Andreas Raab wrote:
>> Folks -
>>
>> I wanted to make the property whether to show individual processes in
>> MessageTally a preference and couldn't recall any of the three
>> gazillion methods to create one ;-) So I decided enough is enough and
>> added the ability to register a preference via Pragma. In other
>> words, you specify two class side accessors (using MessageTally as
>> example):
>>
>> showProcesses
>>     "Indicates whether to show each process separately or cumulatively."
>>     <preference: 'Show Processes in MessageTally'
>>         category: 'debug'
>>         balloonHelp: 'If enabled, each profiled process is shown
>> individually in MessageTally'
>>         type: #Boolean>
>>     ^ShowProcesses
>
> Looking at your version I see you made some slightly different design
> choices than in the design that has been in design discussion and
> worked on in the last couple of weeks on the Pharo list.
>
> Can you elaborate what motivated the different design? Meaning what
> parts of the Pharo version could be made better? Or, sorry for
> basically asking the same thing three times, what would it take to
> adopt the Pharo version for Squeak?
>
> Michael
>
>
Hallelujah,

thank you Michael

Keith


Reply | Threaded
Open this post in threaded view
|

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

Igor Stasenko
In reply to this post by Bert Freudenberg
2009/3/5 Bert Freudenberg <[hidden email]>:

> - Show quoted text -
> On 05.03.2009, at 00:34, Michael Rueger wrote:
>
>> Andreas Raab wrote:
>>>
>>> Folks -
>>> I wanted to make the property whether to show individual processes in
>>> MessageTally a preference and couldn't recall any of the three gazillion
>>> methods to create one ;-) So I decided enough is enough and added the
>>> ability to register a preference via Pragma. In other words, you specify two
>>> class side accessors (using MessageTally as example):
>>> showProcesses
>>>   "Indicates whether to show each process separately or cumulatively."
>>>   <preference: 'Show Processes in MessageTally'
>>>       category: 'debug'
>>>       balloonHelp: 'If enabled, each profiled process is shown
>>> individually in MessageTally'
>>>       type: #Boolean>
>>>   ^ShowProcesses
>>
>> Looking at your version I see you made some slightly different design
>> choices than in the design that has been in design discussion and worked on
>> in the last couple of weeks on the Pharo list.
>>
>> Can you elaborate what motivated the different design? Meaning what parts
>> of the Pharo version could be made better? Or, sorry for basically asking
>> the same thing three times, what would it take to adopt the Pharo version
>> for Squeak?
>
>
> Hmm, at least I am not aware of what is going on in Pharoland. I'm reluctant
> to subscribe to the Pharo list. Not because I'm not interested, but because
> for one my spare time is already filled up by Etoys+Squeak+OLPC+Sugar, and
> also because the Pharo creators went to their own playground specifically to
> get away from certain opinions on squeak-dev. I feel like I shouldn't haunt
> them uninvitedly.
>
> I wonder if someone could summarize what's going on on the greener side,
> like the weekly excerpts we sometimes get for squeak-dev ... or is there
> such a thing for Pharo already?
>
> Anyway, I think it's great you point out this existing design. Duplication
> of effort is not something we should put up with in our small community. Do
> you have a direct pointer to the code in question?
>

Well, it can be seen at different angle  - a competition. If so, then
this is good as well - both vendors will try best to make own
framework better than others :)
And of course, if they decide to join efforts, both will win.

> - Bert -
>


--
Best regards,
Igor Stasenko AKA sig.

Reply | Threaded
Open this post in threaded view
|

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

Andreas.Raab
In reply to this post by Michael Rueger-6
Michael Rueger wrote:
> Looking at your version I see you made some slightly different design
> choices than in the design that has been in design discussion and worked
> on in the last couple of weeks on the Pharo list.
>
> Can you elaborate what motivated the different design? Meaning what
> parts of the Pharo version could be made better? Or, sorry for basically
> asking the same thing three times, what would it take to adopt the Pharo
> version for Squeak?

Good question. I'm not (yet?) in a position to answer it. But it would
be good if you could point people to the code so they can look at it.
And if you would like to get it into 3.11 have please follow the process
described here:

http://lists.squeakfoundation.org/pipermail/squeak-dev/2009-February/134095.html

As for my variant, I wouldn't actually call it much of design ;-) More
like the simplest thing that I could possibly come up with and that
would work in the time frame that I had myself allowed to do it. If I
would have allowed myself a bit more time on it I would have done things
differently: I was thinking about exposing the actual class variable as
the preference object. In other words, the spec would've looked like:

   <preference: #ClassVarName
      label: 'Preference label'
      category: 'PrefCategory'
      balloonHelp: 'Your help goes here'
      type: #TypeName>

and it would result in Preferences looking up the class var and using it
directly. The reason I like this better is that it allows the preference
to be implicitly synchronized. Since preference and class variable are
the same object, they cannot get out of sync (the version I posted
allows setting the value without updating the preference).

Exposing the class variable as preference also allows some interesting
uses like project- (or process-) local preferences simply by using a
different type of variable binding. I have recently been playing with
ProjectLocalBindings which redirect access to Project current to allow
for different values of our old friends Display and Sensor and it has
proven very fruitful. Preferences would be another very natural
application for these bindings. But obviously, this is more work (and it
didn't look pretty when I checked PreferenceValue and friends) so I just
wasn't up for it so I choose the easy way out ;-)

In any case, I'm not wed to my implementation. It's simple and
non-intrusive (which is good), it doesn't expose any of the internals
like PreferenceValue, PreferenceViewRegistry etc (which is good) but
other than that I have zero attachment to it. If there is a better
implementation that's out there let's just use that. The one desire I
would have for that implementation is that it allows taking out all the
preferences stuff for systems which don't provide a UI for it. I would
like to be able to add preferences in this form to some fairly low level
parts of the system and tying it into the presentation layer would be a
mistake for that.

Cheers,
   - Andreas

PS. I'm only posting this to Squeak-dev since I have a distinct feeling
that my comments wouldn't be very welcome on the Pharo list. Please feel
free to forward it and correct me if I am mistaken.

Reply | Threaded
Open this post in threaded view
|

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

NorbertHartl

>
> PS. I'm only posting this to Squeak-dev since I have a distinct feeling
> that my comments wouldn't be very welcome on the Pharo list. Please feel
> free to forward it and correct me if I am mistaken.
>
Come on, guys! To be honest for me there are too much subtle things
floating around here the last weeks. How can we think about building a
common base for squeak, pharo et al. if there is so much emotional
cruft lying in the way?

I personally regard your posts quite well. There is always much sense
in there. And...sometimes I do not agree. And that is the same for the
other "old guys".

So I don't see any reason why you should not post such things on pharo
because the topic was already cross-squeak-pharoish.

You know it's just.....

...I don't like cross-posting ;)

Norbert


Reply | Threaded
Open this post in threaded view
|

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

Andreas.Raab
Norbert Hartl wrote:
>> PS. I'm only posting this to Squeak-dev since I have a distinct feeling
>> that my comments wouldn't be very welcome on the Pharo list. Please feel
>> free to forward it and correct me if I am mistaken.
>>
> Come on, guys! To be honest for me there are too much subtle things
> floating around here the last weeks. How can we think about building a
> common base for squeak, pharo et al. if there is so much emotional
> cruft lying in the way?

 From my side it is not emotional cruft. It is respect for their
decision. Anyone should be allowed to do what they'd like to do with the
people they'd like to do it. I don't feel invited (for good reasons I
think) and I don't want to intrude other people's private space. If this
is mistaken I'm open to changing it, but until I see evidence for that I
think it is wiser to leave the Pharo folks their own space.

Cheers,
   - Andreas


Reply | Threaded
Open this post in threaded view
|

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

Edgar J. De Cleene
In reply to this post by Andreas.Raab



On 3/5/09 1:53 AM, "Andreas Raab" <[hidden email]> wrote:

>
> PS. I'm only posting this to Squeak-dev since I have a distinct feeling
> that my comments wouldn't be very welcome on the Pharo list. Please feel
> free to forward it and correct me if I am mistaken.

I trust you and your implementation should go to current .image ASAP.
If at some point some guy of different secta come with a better code, we don
reject for "heretic" =:)

Edgar




Reply | Threaded
Open this post in threaded view
|

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

Andreas.Raab
Edgar J. De Cleene wrote:
> I trust you and your implementation should go to current .image ASAP.
> If at some point some guy of different secta come with a better code, we don
> reject for "heretic" =:)

To the contrary. Let's give collaboration a chance. It would be stupid
if we ended up with just enough difference to make us incompatible at
such a superficial level. At the very least we should be waiting for a
week or two to see if there's any reaction from the Pharo folks. Even if
there is no reaction we should try to make it compatible at the
interface (pragma) level. I'd be willing to do at least that but I'd
need to know what their pragma spec actually looks like (can anyone
subscribed to Pharo post an example or point me to ti?)

Cheers,
   - Andreas

Reply | Threaded
Open this post in threaded view
|

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

Igor Stasenko
http://n2.nabble.com/Preference-refactoring-again-tt2403814.html

2009/3/5 Andreas Raab <[hidden email]>:

> Edgar J. De Cleene wrote:
>>
>> I trust you and your implementation should go to current .image ASAP.
>> If at some point some guy of different secta come with a better code, we
>> don
>> reject for "heretic" =:)
>
> To the contrary. Let's give collaboration a chance. It would be stupid if we
> ended up with just enough difference to make us incompatible at such a
> superficial level. At the very least we should be waiting for a week or two
> to see if there's any reaction from the Pharo folks. Even if there is no
> reaction we should try to make it compatible at the interface (pragma)
> level. I'd be willing to do at least that but I'd need to know what their
> pragma spec actually looks like (can anyone subscribed to Pharo post an
> example or point me to ti?)
>
> Cheers,
>  - Andreas
>
>



--
Best regards,
Igor Stasenko AKA sig.

Reply | Threaded
Open this post in threaded view
|

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

Andreas.Raab
Igor Stasenko wrote:
> http://n2.nabble.com/Preference-refactoring-again-tt2403814.html

Oh. That is indeed quite similar. Two comments:

* There is really no need to specify a #setter: in the pragma - the name
of the setter can be derived from the getter (read-only preferences
would be pointless, no? ;-)

* There is really no need to specify the default explicitly - it can be
derived from the current value when the preference is registered.

Other than that it looks good. It would be trivial to adjust my version
to use this pragma pattern but I would still prefer it if we could
collaborate on the implementation.

Cheers,
   - Andreas

> 2009/3/5 Andreas Raab <[hidden email]>:
>> Edgar J. De Cleene wrote:
>>> I trust you and your implementation should go to current .image ASAP.
>>> If at some point some guy of different secta come with a better code, we
>>> don
>>> reject for "heretic" =:)
>> To the contrary. Let's give collaboration a chance. It would be stupid if we
>> ended up with just enough difference to make us incompatible at such a
>> superficial level. At the very least we should be waiting for a week or two
>> to see if there's any reaction from the Pharo folks. Even if there is no
>> reaction we should try to make it compatible at the interface (pragma)
>> level. I'd be willing to do at least that but I'd need to know what their
>> pragma spec actually looks like (can anyone subscribed to Pharo post an
>> example or point me to ti?)
>>
>> Cheers,
>>  - Andreas
>>
>>
>
>
>


Reply | Threaded
Open this post in threaded view
|

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

cedreek
2009/3/5 Andreas Raab <[hidden email]>:
> Igor Stasenko wrote:
>>
>> http://n2.nabble.com/Preference-refactoring-again-tt2403814.html
>
> Oh. That is indeed quite similar. Two comments:
>

there's only this suggestion:
http://n2.nabble.com/A-few-more-ideas-about-preferences-td2428084.html

--
Cédrick

Reply | Threaded
Open this post in threaded view
|

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

Andreas.Raab
In reply to this post by Michael Rueger-6
Hi -

To get back to the original question, Michael Rueger wrote:
> Looking at your version I see you made some slightly different design
> choices than in the design that has been in design discussion and worked
> on in the last couple of weeks on the Pharo list.
>
> Can you elaborate what motivated the different design? Meaning what
> parts of the Pharo version could be made better?

Now that I've looked at Alain's code I can make a clearer statement
about it. I was misled a little at first by the similarities in the
pragma spec but the philosophy behind both implementations is actually
fairly different.

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):

gradientButtonLook
        <preference: 'Gradient look for buttons' type: #Boolean set:
#gradientButtonLook: defaultValue: true description: 'Gradient look for
buttons'>
        ^ GradientButtonLook
                ifNil: [GradientButtonLook := PreferenceValue
                                                value: true
                                                location: self
                                                selector: #gradientButtonLook]

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.

My approach differs in such that it is aimed at being discoverable
without introducing any dependencies. To illustrate, please load the
latest (updated) version via:

Installer mantis bug: 7306 fix: 'PreferencePragmas.2.cs'.
Preferences registerForEvents.

And then do the following. Go into class MessageTally (to stay on-topic
;-) and change the method #defaultPollPeriod to read:

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 ]

(yes, the spec has changed a tiny bit; I like Alain's 'description'
terminology better) Accept the method and open a preference browser.
Voila! There is a brand new "Profiling" category which allows you to set
MessageTally's default poll period. No further changes required.

However, since this was discovered via pragmas, no dependency between
Preferences and MessageTally has been created. 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.

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.

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 hope this makes the conceptual difference clear.

Cheers,
   - Andreas


Reply | Threaded
Open this post in threaded view
|

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

keith1y

>
> 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.
>
> 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 hope this makes the conceptual difference clear.
>
> Cheers,
>   - Andreas
Sounds good,

I will definitely be adopting this in a few packages.

Keith


Reply | Threaded
Open this post in threaded view
|

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

Alain Plantec
In reply to this post by Andreas.Raab
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
>
>
>




Preference tree.png (57K) Download Attachment
Reply | Threaded
Open this post in threaded view
|

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

Edgar J. De Cleene
In reply to this post by keith1y



On 3/6/09 3:44 AM, "Keith Hodges" <[hidden email]> wrote:

>
>>
>> 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.
>>
>> 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 hope this makes the conceptual difference clear.
>>
>> Cheers,
>>   - Andreas
> Sounds good,
>
> I will definitely be adopting this in a few packages.
>
> Keith

I beg you do a .cs and put in the updates with all Andreas say about this
and about Announcements.

Squeak newbies like hit the updates button and have the up to day
3.10.x.nnnn.image

Edgar




Reply | Threaded
Open this post in threaded view
|

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

keith1y
In reply to this post by Alain Plantec
I would like to see a simpler approach that may still be effective in
Kernel images with the minimal of scafolding, and I am still slightly
edgy about pragmas. (can anyone remember how Smalltalk Agents used to
use "directives"? I cant, but I seem to recall they were a similar idea).

Here is an idea:

Have classes PreferenceDefaults, PreferenceOptions, and
PreferenceValues, and have your package add method extensions to it. So
Monticello adds

PreferenceDefaults-#prefUseAtomicLoading

    ^ true


PreferenceDefaults subclass: PreferenceValues-#prefUseAtomicLoading

    ^ true

PreferenceOptions-#prefUseAtomicLoading

    ^ {

    'Enable atomic loading' -> true.
    'Disable atomic loading' -> false.

    }

If you want to subclass PreferenceValues, for PreferenceUIValues, so
that a number of your UI  packages become aware of PreferenceValues ui
prefScrollBarsOnRight (still use only one global in your client code if
possible)

Implementers of #prefUseAtomicLoading tells you all there is to know, -
who defined it, default value, possible values, current value.

You can save the preferences form the image in a file out of the class
Preferences.

If you have a subdomain that wants to use different values, define a
subclass of PreferenceValues, and inherit the defaults and current
setting, or inherit PreferenceDefaults and provide your own, (overriding
#ui to return ^self if you want to provide values for the
PreferenceUIValues).

You can easily have one preference depend upon the value of another, or
upon simple rules.

PreferenceDefaults-prefUseAtomicLoading  ^ (Smalltalk classNamed:
#SystemEditor) notNil

In this manner you have a preferences system which needs "no code".
Discovery is a simple walk of the tree of PreferenceValues.

If you want to watch for preference changes, you can simply subscribe to
whatever system changes modification event mechanism is in place.

Keith






Reply | Threaded
Open this post in threaded view
|

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

Andreas.Raab
In reply to this post by Alain Plantec
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

123