[Zope3-dev] default and required analysis

Martijn Faassen faassen@vet.uu.nl
Wed, 8 Jan 2003 00:48:52 +0100


Default and Required in Schema and Forms

Note that this document is just an analysis of the situation and
various possibilities, not a proposal. See this as 'use
cases'. Perhaps there are use cases I haven't considered yet; please
give feedback and make actual proposals..

Definitions for this text:

  * field: a specification of an attribute/property in an interface,
    as opposed to a method.

  * property: a published attribute of an object that implements a
    field. This does not specify how this is implemented; may be a
    simple attribute or using python's property() mechanism or may use
    descriptors, etc.

  * schema: an interface that contains fields (not only method
    spefications).

  * widget: a view representing a field in a UI (such as HTML).

  * form: a bunch of widgets displayed together. Some of them may be
    altered by the user. There is a way to submit the current state of
    the form to the server in a request.

There are a number of different possible meanings of a field being
'required':

  * existence, applies to property: the object implementing the
    schema must have a property of that name. If a field is not
    required, the property may be absent.

  * not-Noneness, applies to property value: the object implementing
    the schema must have a property and its value is not allowed be
    'None'. If the field is not required, that property may be
    'None'. The property must always exist.

  * Form requiredness: in a form based on a schema, the user must
    enter some value in the widget (or at least the value must be
    submitted), otherwise there will be an error (ConversionError in
    form or ValidationError in schema?). If not required, the user can
    safely not fill in anything into the widget at all.

    What 'no value' means depends on the widget; in some circumstances
    entering only whitespace may mean 'no value', in other
    circumstances one could imagine it does there is a value (a
    whitespace string). Some widgets don't have explicit settings for
    'no value' (for instance, a checkbox).

    In HTML forms, sometimes if the user enters no value there is no
    entry for this in the form data in the REQUEST at all. In other
    cases there may be (such an empty string). Of course this is an
    implementation detail that should be hidden away.

    To make things more complicated, non-requiredness in a form may
    still mean that the property is required to exist and be not None
    on on the underlying content object. When a user submits a form,
    this field may be omitted, and this means the field is left alone
    in the underlying content object. There may still be a widget
    *displaying* the property, or the widget could be ommitted from
    the form altogether.

There are also a number of possible meanings of a field having a
'default':

  * Use if missing: if the user enters no value (whatever this means, see
    above), this value will be used instead.

  * Use if empty: when the user accesses the property and the property
    is empty (whatever that means, perhaps it means the value is
    'None'), use this value instead.

  * In the context of forms, if a user enters no value in a widget
    (value is missing), the form could tell the underlying object
    that the value is 'missing'. This could mean 'use if missing' is
    triggered.

  * In the context of forms, if a form is displayed but the underlying
    value is empty (or possibly this is an add form and the underlying
    object doesn't exist yet?), 'use if empty' is used to display
    fields with values already filled in.

In Python, missingness is frequently signaled by using None, such as
in this pattern::

  def grok(alpha, beta, gamma=None):
      if gamma is None:
         # gamma was either missing in input or user explicitly entered
         # None
         gamma = 4711

as well as this, in the context of Persistence::

  class Foo(Persistent):
      # 'value' is a new property added later in the evolution of the
      # class. Some instances may therefore not have this value yet,
      # but this way it won't break
      value = None 

      def method(self):
         if self.value is None:
             self.value = {}

I would call YAGNI on 'existence'; let's assume that if a field is
specificed in a schema, the objects implementing this schema *must*
have such a field otherwise they are in error.

Pick your combo, post about it, and analyze the tradeoffs.
Separate 'missing' value or is 'None' sufficient? Are there different
tradeoffs if we pick relational database integration instead of forms
to drive our use cases? Etc..

Regards,

Martijn