Preferences revamp redux

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

Preferences revamp redux

Chris Muller-4
>> Gentlemen, may I ask what you thought of my list of requirements?
>>
>>   http://lists.squeakfoundation.org/pipermail/squeak-dev/2016-March/188486.html
> IMHO the first point is not a requirement (what?) at all but a solution (how?).

It depends on who your actor is.  I get your point when the
actor is an end user playing with an iPad, but requirement #1 is
trying to assert that the type of actor for *these* requirements is a
non-programmer user who wants to write a little code or make a little
application that might have a Preference or two.  In that case, the
requirement is that we have a simple, easy to understand English-based
class hierarchy, and not computery terms.

We already have it anyway, so we don't even need to discuss this..

>> I honestly think we don’t need pragmas to do it.
> I agree but I cannot understand why you seem to hate pragmas.

Whoa, I don't "hate" pragma's at all, they're an important capability,
I'm simply saying that using them for our Preferences system makes a
design that is not only unnecessarily complex and confusing but
embarassingly bad and incapable.  We're supposed to be the language of
"objects" but can't even represent a template of Preferences to solve
the most basic of requirements, like #7..!

Meanwhile, Marcel's new Themeing implementation solves the same
problem with a fraction of the code and complexity, and yet is 10X
more powerful.  Its a leveraged design based on objects, instead of
diluted based on dozens of global variables..

>>> the other
>>> is in being modular, in that the pragma method can live in the package to
>>> which it belongs.
>>
>> Let’s not let package concerns dictate the design.
> IMHO packaging concerns are very important design drivers. I consider missing modularity one of the main problems with Smalltalk.

Don't worry, our packaging system is flexible enough that we don't
need to limit our design because of packaging (a developer activity,
BTW).  As I showed earlier in this thread, Pragma preferences provide
no benefit in the area of packaging, every preference accessor can
still be in its own package.  The new theming implementation proves
this, too.

>> snip...

> I don’t understand why you consider pragma more computery whihz-bang than classes, objects and messages. I’d even say they are much simpler to understand than metaclasses. And pragmas are in all commonly used Smalltalk implementations by now.

Because they represent metadata about something "in the computer"
rather than a description of the domain which the power-user actor
cares about.

They're supposed to represent information about methods of the system.
Using them for the user domain models is a confusing mis-use.

We *really should* try harder to target users besides our developer
selves.  Please?  Smalltalk was the only system in which users can
learn to program without learning or caring anything about computers.
If they have to become programmers, then suddenly the whole menu of
more popular languages like Python or Ruby becomes just as accessible
to them.  We keep trying to nullify our Smalltalk advantage..  :(

>> IMO, we should just do Smalltalk and objects.  1) Get rid of teh class
>> vars, 2) change the getter/setters to access Preferences
>> wrapped-dictionary, which still compiles dynamic accessors, if
>> necessary, and 3) hopefully also ditch the pragmas in favor of a
>> protocol selection.
> Please no.

What about requirement #7?

Reply | Threaded
Open this post in threaded view
|

Re: Preferences revamp redux

Eliot Miranda-2
Hi All,

    replying to an earlier message now we have a good subject line :-)


On Sat, Dec 17, 2016 at 2:25 PM, Chris Muller <[hidden email]> wrote:
Gentlemen, may I ask what you thought of my list of requirements?

   http://lists.squeakfoundation.org/pipermail/squeak-dev/2016-March/188486.html

I like some of them.  To be specific...

1.  I see no need for Preferences except as a UI tool.  Preferences are used to control parts of the system that can have useful alternative behaviors.  Having a Preferences UI is useful as it
- informs the user of the set of available preferences and documents them
- provides a convenient UI for setting them
But it is /much/ more preferable for the code that is affected by a given preference to use its own state to determine the value of the preference:
- the application can continue to work if Preferences is unloaded
- the application does not have to restrict itself to the Preferences style and can use something it finds convenient

2. very useful; can easily be derived from pragma preferences

3. Not sure symbolic names are useful.  A user readable name is useful, but an additional symbolic name is just cruft

4. OK, again something that can be included in pragma preferences (and indeed derived from code if the pragma method is stereotypical enough; which it should be)

5. Not sure preferences need to specify the domain of values; boolean preferences are easy, but, take, say, a repository URL.  I don't think it makes sense to restrict this to a fixed set of valid URLs.  So not too sure about 5.

6. Sure.  Again something that can be done with pragma preferences

7. Sure.  Can be constructed from 2. 4. and ability to access current value.

7.5, 7.6 why?  Don't see any pressing need for these.  Seem to be forcing a Dictionary implementation.

8.  Sure.  Again a preference saving/loading mechanism is not antithetical to pragma preferences.

9.  Sure

10.  That's what pragma preferences do.  That's one of the major advantages of pragmas in general.  They allow code to be labelled with semantic information that applies not to the code's function, but to its context in a broader system.  They allow that labelling to be associated with the code to be labelled, not be in a collection of labelling that collide when considering different sets of code to be labelled.

These were derived through careful consideration of the real-world use
cases, both for Squeak and external applications.  They are open for
discussion, of course!

We don't need a special language feature to provide a simple and
elegant wrapping of a Dictionary.  We just need to get back to
Smalltalk and objects.

Um, why is a Dictionary a valid representation of preferences?  A dictionary might adequately tell us the current state of the system's preferences.  But as we've seen above we need a lot more, default value, documentation, UI for changing, save/load framework.


> We're in agreement.  The pragma approach has two main advantages; one it to
> identify and allow documenting methods that provide preferences,

I honestly think we don't need pragmas to do it.

I was agreeing with Bert, not you.  You and I clearly disagree.
 
> the other
> is in being modular, in that the pragma method can live in the package to
> which it belongs.

Let's not let package concerns dictate the design.  Let's make the
right design for users, *then* optimize out any packaging issues that
may arise.  There's no reason Preference accessors can't just as
easily live in the package they belong without needing to use pragma's
and class-vars.

This is not about Monticello packages.  It is about complex systems being composed of components.  Of course I want to deploy a system which is a subset of a more complex one.  Of course I should be able to discard the Preference UI if my application doesn't (or more importantly, can't or shouldn't) support it.

>> But having to implement preference storage over and over again is not the

>> best solution. But that's what the current pragma prefs require - a setter
>> and a getter and a class var and logic for initialization and if a class has
>> many prefs then maybe a prefs dictionary because too many class vars are
>> annoying etc. pp.
>
>
> Well, in the case where code wants to update the preference I think the
> setter is acceptable,.  But it ould be nice if the Preferences package could
> infer how to set the variable from the getter, something i think is fairly
> trivial if the getter returns a class var (or even a class inst var?).
> Also, the getter can (and should) provide the initialization if the body is
> written as
>
>     ^Var ifNil: [Var := true/false/aSymbol]

That's what I thought too, and why I originally argued against
answering arbitrary default value of false, before agreeing, but then
someone mentioned that the developer could have easily misspelled it,
causing a hidden bug.  I couldn't agree more, and that seems like it
really dilutes any net gain for the user.  Its complex and magic,
instead of just simple.

It's not complex or magic.  It's code.  It's an assignment.  The "magic" is the ability to decorate that code with information that
- states that this is a system preference
- documents its purpose
- identifies it to tools that want to collect the set of system preferences
- etc

> So with this approach and help from the Preferences framework one should be

> able to get away with just the getter, whose pragma should; include the
> help[ text, etc, and the revised class definition to declare the class var.
> I'm happy to pay that cost for the modularity and documentation.
>
>> Having actual Preference objects managed by a Preferences class takes care
>> of all of that, once and for all.
>
>
> The main problem is that while a preference object can encapsulate the same
> state as the pragma preference getter method, one also needs code to create
> the object and add it to the framework.  It's that that makes the two
> essentially similar in cost, and makes me dislike the preference objects.
> The preference getter method stands alone, and so can be added and removed
> freely.  In a class such as Compiler or Parser where one may have several
> preferences, one ends up having to edit the method that adds preferences
> whenever adding or removing a preference.  There's a collision.  The pragma
> approach solves these collisions by providing an implicit way to add a
> complex object.  Its analogous to how pragma menu actions allow menus to be
> extended without collision between different extensions.

A pure-Smalltalk pattern can do it.  If we want to co-locate access
and the default value in a lazy accessor like this.

  somePreference
     ^ (Preferences somePreference ifNil:
            [ Preferences
                 addPreferenceNamed: #somePreference
                 description: 'When true it means...'
                 default: theDefaultValueForSomePreference ]) value

As others have said the above is way more complex than a pragma preference.  It also ties the application to the Preference UI.
 

#somePreference resides in the package it lives in, of course.

Okay, accessing the list of all preferences (requirement 2, from my
list) could be done by enumerating all the methods in the system which
are in a 'preferences' category, or something like that.

Um, no.  Enumerating all classes and looking for methods with the relevant pragma(s), yes.
 
Protocols is something that's part of Smalltalk forever, we should
leverage it more.  We could bring more power to the system with some
simple toolage over of our "protocols" that can browse such
programmatic usages..

Dangerous.  Smalltalk/V doesn't have them.  They're not in the ANSI standard.  I've used them and like the power, but they can be like perform on constructed strings, non-obvious.

The current pragma approach with class-vars makes it impossible to
meet the basic requirements at all.

No it does not.
 
It also takes our deployment image from being a pure-and-simple,
traditional Smalltalk -- of just classes, objects and messages -- and
tacks on a new computery whiz-bang concept called a Pragma.  Now, a
lot of users' eyes are gonna glaze over.  They're done.  Their hope
that Squeak was an empowering application tool-kit for non-nerds has
been quashed.  It's in-the-weeds programming afterall.   :(

Um, pragmas are in the base system for things like unwind-protect and primitives.  The syntax has been there since Smalltalk-80 (or even 76?).  Message has been there from the get-go.  Pragmas are proving themselves useful in many contexts.  They can no longer be considered whizz-bang magic.  We use them a lot.  They're nice exactly because one mechanism has general uses, unlike, for example, the Preferences framework, which ties code to a clumsy "wrapping of a dictionary", instead of allowing code to express itself as it chooses, and identify its choices to external tools to operate upn it only when desirable..

> But to achieve
> this elegance the pragma scheme must be thought through; for example
> extending the Preference system to allow preferences to be set without
> needing preference setter methods (and maybe even modifying the compiler to
> declare variables in pragma preference methods as class vars?).

It's just a wrapped Dictionary!  Isn't it?

No.  Not at all.  A Dictionary may be a useful thing to present in response to 2. but other than that its implementation driving design.
 

Friends, IMO, Squeak's potential beyond our little group of developer
dudes lies in the how well we can bring the power of the class library
to regular, non-programmer *users*.  People who don't identify
themselves as programmers, but want something more powerful than a
spreadsheet.  Right now, I believe that's still possible.  But I
believe designing Squeak around our developer-centric selves,
increasing usage of whiz-bang language features will not get us there.
IMO the philosophy of staying as simple and traditional and fighting
complexity as long as we possibly can, will improve chances of wider
adoption.

Um, pragmas are in quite a few Smalltalks now.  And I've already defended them against the whizz-bang accusation.
 

IMO, we should just do Smalltalk and objects.  1) Get rid of teh class
vars, 2) change the getter/setters to access Preferences
wrapped-dictionary, which still compiles dynamic accessors, if
necessary, and 3) hopefully also ditch the pragmas in favor of a
protocol selection.

Couldn't disagree more :-)
 

Best.

_,,,^..^,,,_
best, Eliot

On Mon, Dec 19, 2016 at 10:21 AM, Chris Muller <[hidden email]> wrote:
>> Gentlemen, may I ask what you thought of my list of requirements?
>>
>>   http://lists.squeakfoundation.org/pipermail/squeak-dev/2016-March/188486.html
> IMHO the first point is not a requirement (what?) at all but a solution (how?).

It depends on who your actor is.  I get your point when the
actor is an end user playing with an iPad, but requirement #1 is
trying to assert that the type of actor for *these* requirements is a
non-programmer user who wants to write a little code or make a little
application that might have a Preference or two.  In that case, the
requirement is that we have a simple, easy to understand English-based
class hierarchy, and not computery terms.

We already have it anyway, so we don't even need to discuss this..

>> I honestly think we don’t need pragmas to do it.
> I agree but I cannot understand why you seem to hate pragmas.

Whoa, I don't "hate" pragma's at all, they're an important capability,
I'm simply saying that using them for our Preferences system makes a
design that is not only unnecessarily complex and confusing but
embarassingly bad and incapable.  We're supposed to be the language of
"objects" but can't even represent a template of Preferences to solve
the most basic of requirements, like #7..!

Meanwhile, Marcel's new Themeing implementation solves the same
problem with a fraction of the code and complexity, and yet is 10X
more powerful.  Its a leveraged design based on objects, instead of
diluted based on dozens of global variables..

>>> the other
>>> is in being modular, in that the pragma method can live in the package to
>>> which it belongs.
>>
>> Let’s not let package concerns dictate the design.
> IMHO packaging concerns are very important design drivers. I consider missing modularity one of the main problems with Smalltalk.

Don't worry, our packaging system is flexible enough that we don't
need to limit our design because of packaging (a developer activity,
BTW).  As I showed earlier in this thread, Pragma preferences provide
no benefit in the area of packaging, every preference accessor can
still be in its own package.  The new theming implementation proves
this, too.

>> snip...

> I don’t understand why you consider pragma more computery whihz-bang than classes, objects and messages. I’d even say they are much simpler to understand than metaclasses. And pragmas are in all commonly used Smalltalk implementations by now.

Because they represent metadata about something "in the computer"
rather than a description of the domain which the power-user actor
cares about.

They're supposed to represent information about methods of the system.
Using them for the user domain models is a confusing mis-use.

We *really should* try harder to target users besides our developer
selves.  Please?  Smalltalk was the only system in which users can
learn to program without learning or caring anything about computers.
If they have to become programmers, then suddenly the whole menu of
more popular languages like Python or Ruby becomes just as accessible
to them.  We keep trying to nullify our Smalltalk advantage..  :(

>> IMO, we should just do Smalltalk and objects.  1) Get rid of teh class
>> vars, 2) change the getter/setters to access Preferences
>> wrapped-dictionary, which still compiles dynamic accessors, if
>> necessary, and 3) hopefully also ditch the pragmas in favor of a
>> protocol selection.
> Please no.

What about requirement #7?




--
_,,,^..^,,,_
best, Eliot


Reply | Threaded
Open this post in threaded view
|

Re: Preferences revamp redux

Eliot Miranda-2
Hi All,

   from Chris's requirement #4,  4) Ability to ask any Preference its default value, without resetting its current value, here's some simple code for extracting the default value from a pragma preference method, if it specifies a literal default value.

The three styles of providing defaults in pragma preferences are essentially

    ^ClassVar ifNil: [#someDefaultLiteral]

    ^ClassVar ifNil: [ClassVar := #someDefaultLiteral]

    anything else (and we'll see all of these soon).

Looking at the byte codes for the first two forms we see 

21 <40> pushLit: ThoroughSenders
22 <88> dup
23 <73> pushConstant: nil
24 <C6> send: ==
25 <99> jumpFalse: 28
26 <87> pop
27 <71> pushConstant: true
28 <7C> returnTop

and
21 <40> pushLit: ShowSugarNavigator
22 <88> dup
23 <73> pushConstant: nil
24 <C6> send: ==
25 <9B> jumpFalse: 30
26 <87> pop
27 <72> pushConstant: false
28 <81 C0> storeIntoLit: ShowSugarNavigator
30 <7C> returnTop

CompiledMethod provides abstractBytecodeMessagesDo: to enumerate over the byte codes independently of the byte code set's encoding.  So this extracts the default value from one of the two above:

| literal |
self abstractBytecodeMessagesDo:
[:msg|
msg selector == #pushConstant:
ifTrue: [literal := msg argument]
ifFalse:
[msg selector == #methodReturnTop ifTrue: [^literal].
msg selector ~~ #storeIntoLiteralVariable: ifTrue:
[literal := nil]]].
literal

It works by identifying any literal via "msg selector == #pushConstant:" and stores it in literal.  Then if it sees anything other than #methodReturnTop or #storeIntoLiteralVariable: it nils the literal.  And it returns the value of literal as soon as it sees #methodReturnTop.

So the following browses all the pragma preferences in the system that don't fit the first two pattens:

self systemNavigation browseAllSelect:
[:m|
(m pragmaAt: #preference:category:description:type:) notNil
and: [| literal |
m abstractBytecodeMessagesDo:
[:msg|
msg selector == #pushConstant:
ifTrue: [literal := msg argument]
ifFalse:
[(msg selector ~~ #methodReturnTop
 and: [msg selector ~~ #storeIntoLiteralVariable:]) ifTrue:
[literal := nil]]].
literal isNil]]

Of 121 pragma preference methods in my system 22 don't fit the pattern.  Some are project-specific preferences that defer to Project's own custom preference framework, which is necessary to allow individual projects to have their individual preferences (something that the dictionary of preferences framework also cannot handle without special accommodation).  Some are bad examples:

booleanPref
<preference: 'Boolean Preference Example'
category: 'Examples'
description: 'A simple example for a boolean preference  (see PreferenceExample>>booleanPref)'
type: #Boolean>
^BooleanPref

Some are richer:
activeColor
<preference: 'Corner Grip highlight color'
category: 'colors'
description: 'The highlight-color of window corners'
type: #Color>
^(self activeForm colorAt: 24@24) alpha:  1

But I hope you get the point that with very little machinery we can extract the default value in a substantial majority of cases.

Since we'd also like to get rid of the setter it would be good to be able to extract the class variable so it can be set simply by sending it #value: , so... allow me to add abstractBytecodeMessages, then something similar to the following (*)

(((method abstractBytecodeMessages first: 5) collect: [:ea| ea selector]) hasEqualElements: #(#pushLiteralVariable: #doDup #pushConstant: #send:super:numArgs: #jump:if:)) ifTrue:
[^(method abstractBytecodeMessageAt: method initialPC) argument]

answers the class variable, allowing the Preference UI to
- derive its current value
- reset its value given the default extracted above

(*) one could insist on the send being of #== and the pushConstant: supplying nil.

So with these two pieces of machinery in the Preferences UI we don't need setter methods for pragma preferences at all. Note that none of the bytecode magic has to be visible to the author of a pragma preference, but i does have to be understood by the maintainer of the Preference UI.

HTH
_,,,^..^,,,_
best, Eliot


Reply | Threaded
Open this post in threaded view
|

Re: Preferences revamp redux

Chris Muller-3
In reply to this post by Eliot Miranda-2
Hi Eliot,

> 1.  I see no need for Preferences except as a UI tool.

I do.  Most definitely.  You're an expert VM developer.  I'm one of
your customers wanting to applications which can use it, but
currently, can't.

> Preferences are used
> to control parts of the system that can have useful alternative behaviors.
> Having a Preferences UI is useful as it
> - informs the user of the set of available preferences and documents them
> - provides a convenient UI for setting them
> But it is /much/ more preferable for the code that is affected by a given
> preference to use its own state to determine the value of the preference:
> - the application can continue to work if Preferences is unloaded

A "Preference" can relate to anything.  Users want to be able to
"prefer" certain aspects even at the Kernel level.  They're as
universally relevant as Collections.  So the Preferences domain
capability (NOT the UI) should be assumed to be part of the core set
of packages (Kernel, Collections, et al).

The Preferences model is just two simple classes.  There is not a lot
to be gained by unloading them, even on a Raspberry pi.

> - the application does not have to restrict itself to the Preferences style
> and can use something it finds convenient

An application already does not have to restrict itself (unless they
want to commit to your byte-code-analyzing solution), but I think
they should have the option to participate in a capable and
understandable Preferences system provided by Squeak that lets them
reap the capabilities described by these requirements.

> 2. very useful; can easily be derived from pragma preferences

Its very useful, but no one did it because its _not_ so easy for
anyone other than Smalltalk expert developers.  Unfortunately, they're
too busy developing awesome VM's and stuff..   ;)

> 3. Not sure symbolic names are useful.  A user readable name is useful, but
> an additional symbolic name is just cruft

I want to be able to #perform: them.

> 4. OK, again something that can be included in pragma preferences (and
> indeed derived from code if the pragma method is stereotypical enough; which
> it should be)

No one will engage in doing such a derivation before asking themselves,
"why am I doing this instead of just rolling my own object?"

> 5. Not sure preferences need to specify the domain of values; boolean
> preferences are easy, but, take, say, a repository URL.  I don't think it
> makes sense to restrict this to a fixed set of valid URLs.  So not too sure
> about 5.

No one said anything about restricting anything.  This is just a
convenience extension, not very important, but instead of only having

    [true | false]

it would be nice to if the user could cycle through things like:

     [small | medium | large]
     [trunk | inbox | squeak51]

Again, only for UI pre-population convenience, it does NOT imply
any sort of restriction from the user entering their own URL
whatsoever.  Okay?

> 6. Sure.  Again something that can be done with pragma preferences
> 7. Sure.  Can be constructed from 2. 4. and ability to access current value.

"Can" be.  'Nuff said...

Does it strike you how many of your solutions require you to scan the
system, collect up the preferences into temporary collections, again
and again?   Like a relational database application.  The object
solution demonstrated by UserInterfaceTheme did not have to sacrifice
any of your packaging requirements, yet already easily solves this
requirement and more.

> 7.5, 7.6 why?  Don't see any pressing need for these.  Seem to be forcing a
> Dictionary implementation.

To support ReleaseBuilder.  It does not force a Dictionary implementation.

> 8.  Sure.  Again a preference saving/loading mechanism is not antithetical
> to pragma preferences.

Eliot, I'm sorry, but storing preference values in a bunch of global
variables scattered all throughout the system IS antithetical to
saving/loading entire sets of preferences...

> 9.  Sure

But we can't do it!  I want the ability to adjust all my
#fontPreferences independently of my #colorPreferernces independently
of my #desktopBackground independently of my #systemPreferences.

As a user, I cannot begin to use Squeak's preferernce system to do this.
Nor could the new Theming introduced in 5.1, which is why we
rolled our own -- UserInterfaceTheme, even though it solves the same
basic problem described by these requirements.  There is no dynamic
model
available in the Pragma prefs, only static values encoded in CompiledMethods.

Another requirement is, the ability to *override* preferences in
more-specific contexts (like previewing a theme), but "fall back" to
the more global one if a for the preference value which were not
overridden.

Static Pragma prefs have no ability to do this.

> 10.  That's what pragma preferences do.  That's one of the major advantages
> of pragmas in general.

This can be done anyway.  Its not an "advantage" of Pragma's at all,
as demonstrated by the new Themeing.

> They allow code to be labelled with semantic
> information that applies not to the code's function, but to its context in a
> broader system.
> They allow that labelling to be associated with the code to
> be labelled, not be in a collection of labelling that collide when
> considering different sets of code to be labelled.

An object can do the same.  Code doesn't need to be labelled, a
preference value merely needs to be associated, from code within its
own package.  We can meet your packaging needs with objects, if only
you're willing to consider Preferences a universal (kernel) thing.

>> These were derived through careful consideration of the real-world use
>> cases, both for Squeak and external applications.  They are open for
>> discussion, of course!
>>
>> We don't need a special language feature to provide a simple and
>> elegant wrapping of a Dictionary.  We just need to get back to
>> Smalltalk and objects.
>
>
> Um, why is a Dictionary a valid representation of preferences?  A dictionary
> might adequately tell us the current state of the system's preferences.  But
> as we've seen above we need a lot more, default value, documentation, UI for
> changing, save/load framework.

I can have one Dictionary representing only the "presentation-mode"
preferences, another Dictionary small-screen preferences, and I can
diff the two, very easily.  I can apply them without affecting my
other system preferences.

Introducing Collections (Dictionary's?) into our model lets us
encapsulate just the changes to a Squeak system (e.g. presentation
mode ON, or OFF).   Substitute (dark) and (light) above, (beginner)
and (expert), etc. with any other subset.  Then we can compare them,
apply them, save them, etc. independently of others in the system.

When are scattered about in global variables, we solved our packaging
concern, but blew up the domain flexibility.  I want to have our cake
and eat it too.  No regular user will try to scrape information from
CompiledMethods when they could just roll their own Dictionary.

>> > the other
>> > is in being modular, in that the pragma method can live in the package
>> > to
>> > which it belongs.
>>
>> Let's not let package concerns dictate the design.  Let's make the
>> right design for users, *then* optimize out any packaging issues that
>> may arise.  There's no reason Preference accessors can't just as
>> easily live in the package they belong without needing to use pragma's
>> and class-vars.
>
>
> This is not about Monticello packages.  It is about complex systems being
> composed of components.

Scattering them into global vars is the opposite of being composed of
components.

> Of course I want to deploy a system which is a
> subset of a more complex one.  Of course I should be able to discard the
> Preference UI if my application doesn't (or more importantly, can't or
> shouldn't) support it.

The UI, yes.  But your app still must access its preferred values, and
Preference and Preferences is just two classes, so what is the
problem?

>> That's what I thought too, and why I originally argued against
>> answering arbitrary default value of false, before agreeing, but then
>> someone mentioned that the developer could have easily misspelled it,
>> causing a hidden bug.  I couldn't agree more, and that seems like it
>> really dilutes any net gain for the user.  Its complex and magic,
>> instead of just simple.
>
>
> It's not complex or magic.  It's code.  It's an assignment.  The "magic" is
> the ability to decorate that code with information that
> - states that this is a system preference
> - documents its purpose
> - identifies it to tools that want to collect the set of system preferences
> - etc

Eliot, when we talk to new users about how Smalltalk works, they learn
that objects must be able to understand the messages they send.
Taht's the 99% case, right?

So having this in a part of the system which should be at the *user-level*:

    Preferences someMispelledPreferenceName

silently answer "false", I'm sorry but, to them, its magic.  Its also
a nightmare for debugging even for experienced developers, and totally
unnecessary in a lifecycle that involves testing.

>> A pure-Smalltalk pattern can do it.  If we want to co-locate access
>> and the default value in a lazy accessor like this.
>>
>>   somePreference
>>      ^ (Preferences somePreference ifNil:
>>             [ Preferences
>>                  addPreferenceNamed: #somePreference
>>                  description: 'When true it means...'
>>                  default: theDefaultValueForSomePreference ]) value
>
>
> As others have said the above is way more complex than a pragma preference.

Who said anything about the above?  I'll have to go back and look..

Using a meta-level langauge concept to represent the user domain
unnecessarily is more complex than simply using the regular objects.

> It also ties the application to the Preference UI.

You used this as the basis of several of your arguments, but it does
NOT tie it to the Preference UI.  It ties it to the Preferences class,
which is a kernel-level concept.

>> #somePreference resides in the package it lives in, of course.
>>
>> Okay, accessing the list of all preferences (requirement 2, from my
>> list) could be done by enumerating all the methods in the system which
>> are in a 'preferences' category, or something like that.
>
> Um, no.  Enumerating all classes and looking for methods with the relevant
> pragma(s), yes.

Whether we do this with existing infrastrucutre (protocols) or pragmas
is less important that the global-variable storage, because that's the
source of the inability to repsent preferences in a usable object
model.

>> Protocols is something that's part of Smalltalk forever, we should
>> leverage it more.  We could bring more power to the system with some
>> simple toolage over of our "protocols" that can browse such
>> programmatic usages..
>
> Dangerous.  Smalltalk/V doesn't have them.  They're not in the ANSI
> standard.

No problem, even if Smalltalk/V wanted to adopt Squeak's preference
system, they wouldn't be able to without some manual porting effort
anyway.  They can change to use Pragma's or something else..

> I've used them and like the power, but they can be like perform
> on constructed strings, non-obvious.

They're something that regular and beginning users are exposed to.  By
contrast, parsing bytecodes, hiding setters, etc., -- are much less
obvious.  I suggested some toolage.  Anyway, Eliot, you've been
developing a VM for the last years, I wish you would trust me with my
app ideas and user-level interaction needs.  I've put a LOT of thought
into them..

>> The current pragma approach with class-vars makes it impossible to
>> meet the basic requirements at all.
>
>
> No it does not.

Well, I actually need the ability to compare ANY two sets of
Preferences, not just the current settings with the default settings.
You only solved #7 by parsing bytecodes to extract out the default
value (which is insane!).  I need to diff ANY two instances, save/load
them, and arrange them into a hierarchy of overridden prefs.

All of those things can be done with UserInterfaceTheme.  NONE of
those things can be done with Pragma prefs.

>> It also takes our deployment image from being a pure-and-simple,
>> traditional Smalltalk -- of just classes, objects and messages -- and
>> tacks on a new computery whiz-bang concept called a Pragma.  Now, a
>> lot of users' eyes are gonna glaze over.  They're done.  Their hope
>> that Squeak was an empowering application tool-kit for non-nerds has
>> been quashed.  It's in-the-weeds programming afterall.   :(
>
>
> Um, pragmas are in the base system for things like unwind-protect and
> primitives.  The syntax has been there since Smalltalk-80 (or even 76?).
> Message has been there from the get-go.  Pragmas are proving themselves
> useful in many contexts.

Agree, I simply meant (mis)using them to do Preferences.  A said (mis)
because Pragma's are meant to provide meta-descriptions, not represent
part of the user's domain model.

> We use them a lot.  They're nice exactly because one mechanism has general
> uses, unlike, for example, the Preferences framework, which ties code to a
> clumsy "wrapping of a dictionary", instead of allowing code to express
> itself as it chooses, and identify its choices to external tools to operate
> upn it only when desirable..

Instead of saying "clumsy" I wish you would say one single requirement
that cannot be met by my proposal.  I have done that against Pragma's,
but you came up with a "solution" which involved analyzing bytecodes,
which, IIUC, wouldn't solve the requirement of comparing against other than
the default value.

>> > But to achieve
>> > this elegance the pragma scheme must be thought through; for example
>> > extending the Preference system to allow preferences to be set without
>> > needing preference setter methods (and maybe even modifying the compiler
>> > to
>> > declare variables in pragma preference methods as class vars?).
>>
>> It's just a wrapped Dictionary!  Isn't it?
>
>
> No.  Not at all.  A Dictionary may be a useful thing to present in response
> to 2. but other than that its implementation driving design.

I meant to say a "dictionary" not Dictionary.  The *concept* of a
collection of key->value associations.

I started with requirements and ended up thinking about a Dictionary
for implementation.  You started with Pragma's as the "solution" and
then convinced yourself it was the only solution to the problem of
packaging.  It's not.

>> Friends, IMO, Squeak's potential beyond our little group of developer
>> dudes lies in the how well we can bring the power of the class library
>> to regular, non-programmer *users*.  People who don't identify
>> themselves as programmers, but want something more powerful than a
>> spreadsheet.  Right now, I believe that's still possible.  But I
>> believe designing Squeak around our developer-centric selves,
>> increasing usage of whiz-bang language features will not get us there.
>> IMO the philosophy of staying as simple and traditional and fighting
>> complexity as long as we possibly can, will improve chances of wider
>> adoption.
>
> Um, pragmas are in quite a few Smalltalks now.  And I've already defended
> them against the whizz-bang accusation.

As long as we keep ignoring regular users, they will keep ignoring Squeak.

>> IMO, we should just do Smalltalk and objects.  1) Get rid of teh class
>> vars, 2) change the getter/setters to access Preferences
>> wrapped-dictionary, which still compiles dynamic accessors, if
>> necessary, and 3) hopefully also ditch the pragmas in favor of a
>> protocol selection.
>
>
> Couldn't disagree more :-)

Well, I simply can't use it.  No one other than expert developers
will either, until they need something more application-robust, at
which point they'll probably just roll-their-own..   :(