[TransWarp] Constraints on model attributes

Phillip J. Eby pje at telecommunity.com
Mon Jul 28 18:37:37 EDT 2003

At 11:24 PM 7/28/03 +0200, Roché Compaan wrote:
>* Phillip J. Eby <pje at telecommunity.com> [2003-07-28 03:36]:
> > At 10:33 PM 7/27/03 +0200, Roché Compaan wrote:
> >
> > >I started out following the pattern you describe above but as I went
> > >along I realised some attributes belong in the feature definition and
> > >not in the type definition.
> >
> > Judging by your attachment, I'd have to say we disagree quite a bit on
> > which is which.  IMO, your Container, Iterable, Orderable, Enumerable,
> > Bool, Int, and so on are all *types* -- even MinMaxLen.  These are all
> > things that are entirely independent of a structural feature.  (By the 
> way,
> > peak.model offers a built-in enumeration type, as well.)
>I refactored all the class that were previously model.Attributes so that
>they are now types and so that do proper type checks. I have a small
>problem though. Given the following types:
>class MinMaxLen(model.Type):
>     """ Expresses constraints on the length of a value.
>     """
>     min_length = 0
>     max_length = None
>     def mdl_normalize(klass, value):
>         super(MinMaxLen, klass).mdl_normalize(value)

This should presumably be 'value = super(...).mdl_normalize(value)', to 
take advantage of any conversion done by a base class.  Even though it's 
meaningless initially, somebody could create

class Something(MinMaxLen, SomethingElse, Type):

In which case MinMaxLen.mdl_normalize() will be calling 

>How do I set attributes on the referencedType that are needed for
>normalization *without* subclassing the types.

Eh?  That would be a *different* type.  So subclassing would be appropriate.

>To be clear, let's
>say I have a model.Attribute that only allows values in an enumerated
>set and with a maximum length of 4 characters. For example on planet
>Stepford, the beings there are only allowed names John, Mary and Pete
>and their names may not be longer than 4 characters.

Um, why would you do that?  They're already four characters long, so what's 
the extra bit for?

>class Drone(model.Element):
>     class Name(model.Attribute):
>         referencedType = Text
>         # Ugly, doesn't work and just to illustrate what I want to do.
>         referencedType.max_length = 4
>         referencedType.John = model.enum("John")
>         referencedType.Mary = model.enum("Mary")
>         referencedType.Pete = model.enum("Pete")
>         # or
>         referencedType = Text(max_length=4,
>             allowed_values=["John", "Mary", "Pete"])

class DroneName(Enumeration):
     John = Mary = Pete = model.enum()

class Drone(model.Element):
     referencedType = DroneName

And that would be it.  Now, if you wanted to ensure that they were four 
characters long, you could probably do something like:

class DroneName(MinMaxLen, Enumeration, Type):
     max_length = 4
     John = Mary = Pete = model.enum()

>This is where I got stuck previously and implemented what are now types
>as model.Attributes.

I'm not sure why you want to make types into constraints on features.  This 
seems counterintuitive to me, since this is less reusable than just 
creating a type explicitly.  Usually a type is available directly from a 
module, whereas a feature is inside a class.

I suppose I can imagine there being certain types that you don't want to 
call out explicitly because they repeat a lot (e.g. bounded strings), but 
I'd rather address such items on a case-by-case basis with e.g. functions 
to create a new type on the fly.  Hm.  I suppose you could always create 
constraints as IType/ITypeInfo implementations to wrap existing types, e.g.:

class DroneName(Enumeration):
     John = Mary = Pete = model.enum()

class Drone(model.Element):
     referencedType = MinMaxLen(DroneName, max_length=4)

In this case, MinMaxLen wouldn't inherit from model.Type, but would instead 
implement the necessary methods by delegating to the object it wraps (e.g. 
DroneName in this example).

Note that for this to work properly with (for example) XMI, you need to 
delegate mdl_* attributes as well as all the mdl_* methods.

More information about the PEAK mailing list