Accessing values of properties in ancestors

From Director Online Wiki
Jump to: navigation, search

If you are using ancestors, there are times when you want to access the value of an inherited property.

Here is a simplistic example:

-- Script 1
property ancestor
on new(me)
  ancestor = script(2).new()
   put me.pInheritedProperty
  return me
end
-- Script 2
property ancestor
on new(me)
  ancestor = script(3).new()
  return me
end
-- Script 3
property pInheritedProperty
on new(me)
  pInheritedProperty = #success
  return me
end

-- In the Message window:

put script(1).new()
-- #success
-- <offspring "" 1 722ea90>


The instance of script 1 inherits properties from its ancestor, and from its ancestor's ancestor, and so on. The syntax 'me. pInheritedProperty' will return the value of a pInheritedProperty property in the 'me' instance itself, if one exists. If not, Director will look in each instance in the ancestor hierarchy in turn, until it finds a #pInheritedProperty property. If no ancestor possesses such a property, this will provoke a Script Error.


Alternative Syntaxes

The syntax me[#pInheritedProperty] and me.getaProp(#pInheritedProperty) are not equivalent when you are working with instances which have ancestors.

 put me.getaProp(#pInheritedProperty)
  -- Looks for pInheritedProperty at the inheritor's end of
  -- the ancestor hierarchy.  Will return <Void> if the 'me'
  -- instance does not have a pInheritedProperty, even if
  -- such a property exists in an intervening ancestor.
 put me[#pInheritedProperty]
  -- Looks for pInheritedProperty at the ancestor's end of
  -- the ancestor hierarchy.  Will return <Void> if the final
  -- ancestor does not have a pInheritedProperty, even if
  -- such a property exists in an intervening ancestor.

Example

-- Script 1
property ancestor
property pProperty
on new(me)
  ancestor  = script(2).new()
  pProperty = #script1
  put me.pProperty, "me.pProperty"
  put me.getaProp(#pProperty), "me.getaProp(pProperty)"
  put me[#pProperty], "me[#pProperty]"
  put me.getaProp(#pAncestorOnly), "me.getaProp(pAncestorOnly)"
  return me
end
-- Script 2
property ancestor
property pProperty
property pAncestorOnly
on new(me)
  ancestor = script(3).new()
  pProperty = #script2
  pAncestorOnly = #inaccessible
  return me
end
-- Script 3
property pProperty
on new(me)
  pProperty = #script3
  return me
end
-- In the Message window:
put script(1).new()
-- #script1 "me.pProperty"
-- #script1 "me.getaProp(pProperty)"
-- #script3 "me[#pProperty]"
-- <Void>   "me.getaProp(pAncestorOnly)"
-- <offspring "" 1 7093e80>

Bullet-proof Access to Inherited Properties

Here is a handler that will act like me.pProperty, but which will not cause a script error if no instance in the ancestor chain possesses a property named pProperty. Instead, it will return <Void>.

on GetProperty(anObject, aProperty)
  repeat while TRUE
    vValue = anObject.getaProp(aProperty)
    if voidP(vValue) then
      anObject = anObject.getaProp(#ancestor) -- climb the chain
      if ilk(anObject) <> #instance then
        return VOID
      end if
    else
      return vValue
    end if
  end repeat
end GetProperty

The handler above gives you no way of telling whether the given property exists, but has a value of <Void>, or whether no instance in the ancestor hierarchy possesses a property with the given property name. The handler below will return a value from 0 to n, where n is the number of instances in the ancestor hierarchy. The return value will correspond to the level in the hierarchy where the given property is first encountered, or 0 if none of the instances in the hierarchy possess a property with the given name.

on PropertyExists(anObject, aProperty)
   vIndex = 1
  repeat while TRUE
    if voidP(anObject.getaProp(aProperty)) then
      anObject = anObject.getaProp(#ancestor) -- climb the chain
      if ilk(anObject) <> #instance then
        return FALSE
      end if
    else
      return vIndex
    end if
    vIndex = vIndex + 1 -- position in the chain
  end repeat
end PropertyExists