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 |
On Tue, Mar 3, 2009 at 11:03 PM, Andreas Raab <[hidden email]> wrote:
Folks - Great to see you drinking the kool aid :) This is cool. Somehow "all" (many) preferences ought to be defined this way. |
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 |
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 - |
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 > > thank you Michael Keith |
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. |
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. |
> > 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 |
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 |
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 |
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 |
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. |
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 >> >> > > > |
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 |
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 |
> > 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 I will definitely be adopting this in a few packages. Keith |
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. 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 ] > 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 |
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 |
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 |
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 |
Free forum by Nabble | Edit this page |