[squeak-dev] Preferences revamp redux

Chris Muller asqueaker at gmail.com
Sat Dec 24 21:47:37 UTC 2016


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..   :(


More information about the Squeak-dev mailing list