View · Search · Index
No registered users in community xowiki
in last 10 minutes

Re: [Xotcl] nx parameters

From: Gustaf Neumann <neumann_at_wu-wien.ac.at>
Date: Thu, 16 Dec 2010 11:31:35 +0100

Dear Victor,

here is a scripted writeup to address your questions.

-gustaf neumann
===========================================================
package req nx::test
nx::Object create o

# The method setter registers an accessor method for instance
# variables. It provides "set" and "get" operations and value
# checking.

# Register accessor named x
o setter x

# Use the accessor method x as setter
# (set instance variable x to 1; returns 1)
? {o x 1} 1

# Use the accessor method x as getter
# (get the value of the instance variable x; returns 1)
? {o x 1} 1

# Define a setter with a value constraint
o setter x:int
? {o x 3} 3
? {o x a} {expected integer but got "a" for parameter "x"}

# The accessor function can be realized with some more
typing as well
# via the following method. So, the method "setter" does not
provide
# any additional functionality in terms of expressability of the
# language.

o public method y {value:int,optional} {
   if {[info exists value]} {
     return [set :y $value]
   } else {
     return [set :y]
   }
}

? {o y 3} 3
? {o y a} {expected integer but got "a" for parameter "value"}

# Why are accessor function at all provided since instance
variables
# can be accessed as well without these? In nx it is easy
for an
# object to access the own instance variables via variable
resolvers
# (variable names starting with a single colon), butmore work to
# access the variables of other objects. One can use e.g.
the method
# "eval" to execute a script in the context of an object
(and to be
# able to use the variable resolver).

? {o eval {set :x 2}} 2

# So, an accessor method makes the access of public
variables easy, it
# provides the value constraints, one can use interceptors for
# tracing, refinement, etc.

# Ok, why do we need attributes?

# Attributes (as defined by nx) provide all functionalities
provided
# by the setter methods plus
# - some attribute life-cycle management (e.g. default
values), and
# - arbitrary meta-data

# For example, we can define an integer attributed named "z"
with a
# default value.

o attribute {z:int 123}
# return the default value
? {o z} 123
? {o z a} {expected integer but got "a" for parameter "z"}

# The example above is an object specifc attribute. In most
# situations, attributes are defined on the class level.
Attributes
# are inherited to subclasses (setters certainly as well).

nx::Class create Employee {
   :attribute serial_number:int,required
}
nx::Class create Manager -superclass Employee {
   # Project names are upper case, provided as an list,
which might be
   # empty and are per default initialized to the empty list.
   :attribute {projects:upper,0..n {}}
}

Manager create joe -serial_number 4711

# What about the meta-data? I want to use e.g. very special
meta-data,
# such as e.g. time-stamps.

# The method "attribute" creates so-called slot objects,
which are in
# turn nx objects. These slot objects can be initialized
like all
# other nx objects in a scripted way.

nx::Class create C {
   # Create attributes "x" and "y" and script the
initialization of
   # these attributes.
   :attribute x {
     set :timestamp [clock clicks]
   }
   :attribute y {
     set :timestamp [clock clicks]
   }
   :create c1
}

# Print for every slot object the value of the timestamp, if it
# exists.
proc print_slots_and_timestamps {obj} {
   foreach slot [$obj info lookup slots] {
     if {[$slot eval {info exists :timestamp}]} {
       puts "$slot created at [$slot eval {set :timestamp}]"
     }
   }
}
print_slots_and_timestamps c1

#
# Ok. What if I want to use a time-stamp for every attribute
of my
# application without having to write this for every occurance?
#
# Well, use the force, luke. Remember, we have quite a powerful
# underlying framework, supporting e.g. mixin, dynamic call
# definitions, etc.

::nx::Attribute mixin [Class new {
   :method init {} {
     set :timestamp [clock clicks]
     next
   }
}]

nx::Class create D {
   # Create attributes "x" and "y" and script the
initialization of
   # these attributes.
   :attribute x
   :attribute y
   :create d1
}

print_slots_and_timestamps d1

#
# What if i want to use different kinds of attributes, such as
# e.g. persistent attributes and non-persistent attributes,
etc.? How
# can i define my on slotclasses if i need?
#
# Per default, attributes are of the class ::nx::Attribute.
One can
# certainly define subclasses of this class and specify
these classes
# during attribute creation. Since "attribute" is technically a
# method, the syntax is slightly different to the usual object
# creation.
#
# We define now "MyAttribute" as a subclass of
::nx::Attribute with an
# additional attribute named timestamp. The timestamp has
the actual
# timestamp as default.
#
::nx::MetaSlot create MyAttribute -superclass ::nx::Attribute {
   :attribute {timestamp "[clock clicks]"}
}

# Use this type of attribute:
nx::Class create E {
   :attribute x -slotclass MyAttribute
   :attribute y -slotclass MyAttribute
   :create e1
}

print_slots_and_timestamps e1

# A final question: i see that "attribute" is more powerful then
# "setter". Do I need as an enduser the method "setter" at all?
#
# No. I think, we could safely remove it from the default
method set
# for the final release.
#
# One other observation during this writeup: maybe
"slotclass" is to
# crude, we could use "class" or "type" instead (at some earlier
# state, we could not use technically "class"). We will
overthink
# this.