Hello Gustaf,
1. Is there any way to add meta-data to parameters during parameter creation? Specifically I would like to add a time stamp to the the parameter so I can list parameters in the order they were created. 2. Is there a reason why the "object setter" command has to be a two step command, example: [Object create o; o setter s; o s value]. Why can't it be done in one step [o setter s value] ? I guess the same goes for the "object attribute" command. 3. What is difference between "setter" and "attribute"?
Thanks
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.
Thank you very much Gustaf for taking your time to explain this.
On Thu, Dec 16, 2010 at 2:31 AM, Gustaf Neumann neumann@wu-wien.ac.at wrote:
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.
Hello Gustaf,
Although your examples do seem to work on Object objects, the Class instances do not work right. Here is a snippet from your examples:
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
######################################################
if I do [C create c2] and then [print_slots_and_timestamps c2], the actual output is still for instance c1, not c2, also all instances of C class have the following slot in them, which doesn't seem right: ::C::slot::x . Shouldn't it be something like ::c1::slot::x, ::c2::slot::x ?
Thanks
On Thu, Dec 16, 2010 at 2:31 AM, Gustaf Neumann neumann@wu-wien.ac.at wrote:
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.
On 19.12.10 21:37, Victor Mayevski wrote:
Although your examples do seem to work on Object objects, the Class instances do not work right.
They work "right", but maybe not as you expected. You original question was:
Is there any way to add meta-data to parameters during parameter creation? Specifically I would like to add a time stamp to the the parameter so I can list parameters in the order they were created.
The following code snippet adds meta-data to every "attribute" (similar to "-parameters" in XOTcl) when it is created. More technically, the method "attribute" creates a slot-object on the class or object, on which it is created. These slot objects are extended in this example by an additional instance variable named "timestamp".
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 }
Note, that the slot objects are created at the time, when the method "attribute" is called, in the code above at the time, when class "C" is created, before the object c1.
Slot objects provide common meta-data for all their managed instance variables. Typical examples for such meta-data are a default value, a value checker, a linkage to a database table/attribute, the sql-type of the attribute, a label for pretty printing, a widget for data entry, .....). If an attribute is defined on a class, it is created per-class, not per class instance (that would be too costly in most situations).
if I do [C create c2] and then [print_slots_and_timestamps c2], the actual output is still for instance c1, not c2,
of, course, if one creates two instances of C (such as c1 and c2), these will share the same slot objects (in the example above, the slot objects are named C::slot::x and C::slot::y; normally, the names of the slot objects won't interest you).
If you want to create unique timestamps per attribute value, i would recommend to combine a timestamp from the object creation time with the a timestamp from the slot object creation (see below)
best regards -gustaf neumann
======================================== proc print_slots_and_timestamps {obj} { foreach slot [$obj info lookup slots] { if {[$slot eval {info exists :timestamp}]} { puts "$obj has attribute [$slot name] \ timestamp [$obj T].[$slot eval {set :timestamp}]" } } } nx::Class create C { :attribute x {set :timestamp [clock clicks]} :attribute y {set :timestamp [clock clicks]} :attribute {T "[clock clicks]"} :create c1 :create c2 } print_slots_and_timestamps c1 print_slots_and_timestamps c2