#133 Field Design

brian Wed 17 Jan 2007

I checked in what I think is (hopefully) the final design for fields including full support for virtual fields and the field storage @ operator. The design largely sticks with our brainstorming from 17 Dec:

  • a field at its most basic level provides a single logical slot which may be get and set using the dot and assignment operators
  • a field may encompass: a) a storage location, b) default value, c) getter, or d) setter (in various combinations)
  • const fields (and some synthetic fields) contain a storage location only - there is no getter/setter for consts
  • abstract fields have abstract getter/setter but no storage location or default value
  • mixins can have const static fields or abstract instance field (no concrete instance fields)
  • a getter/setter is automatically provided if none specified (except for consts)
  • fields may be abstract in which case they must be overridden
  • fields may be virtual in which case they may be overridden
  • as before you can use a field to override an no-arg method which returns the same value
  • all access to a field by name is thru getter and setter (different than our previous rule where access internal to class was to direct storage)
  • access to field storage is done using the new @ storage operator
  • only the declaring class (or first override of abstract fields) can use @ to access storage directly
  • field initializers set the field directly using storage (keep this in mind if using calculated fields and note one exception to this rule below)
  • if and only if @ is used on a field inside its class's definition will the compiler emit the Storage flag such that the runtime emits an actual storage location for the field (abstract fields, overridden fields, and calculated fields don't actually consume any storage memory)
  • overridden fields can specify a new default value, getter, or setter in any combination - anything not specified is inherited (in the case of overriding an abstract field, then null default, and default getter and setter will be used); Fields which override a concrete field are never given their own storage, and must call super to access the super class's storage location (or calculated storage)
  • it is a compile time error to access a field other than thru @ or super in that field's getter or setter (to catch common mistakes leading to infinite recursion)
  • support for calling field accessors like other methods using the () operator has been removed
  • non-virtual fields without a custom getter/setter are optimized to straight storage calls internal to the pod (field access is much faster than method calls)
  • covariance is not supported in field overrides (jeez I can only imagine how complicated that could get)

brian Thu 18 Jan 2007

One big thing to note is the overriding a field has the unusal characteristic that everything depends on what is actually overridden. When overriding a concrete field (virtual, non-abstract field) this means that we already have a getter/setter and most likely a storage location. When we have this case where a field overrides a concrete field there are some additional rules:

  • we never give the override its own storage, nor do we give it access to the @ operator for that field, rather the field must use super to reuse whatever storage location the superclass is using. Or if you really want you can override the getter/setter to map the value to another field with a different name
  • Another difference is that if a getter/setter isn't specified in an override field, then the auto-generated accessors call the superclass accessors (which is unlike the standard auto-generated accessors which load/save directly to storage)
  • If an initializer is specified in an concrete override, then the intializer uses the accessor (the virtual one, not super) - this differs from standard field initialization which uses storage directly

Overall there was quite an overwhelming amount of details and rules I was trying to keep in my head at once to implement virtual fields (hopefully this post will let me recall them when necessary). However I think the end result is that it just works like most people would expect without thinking too much about it. Certainly there is some potential gotchas when using storage vs calculated fields - but that seems like it will be rare and the common case is that this model should be much simpler and cleaner than the Java (do everything yourself with naming conventions) and C# (combine prop with field yourself) models.

Where things will get real slick is when we add the ability to register methods to wrap field access - maybe something like Py decorators.

Login or Signup to reply.