File: bagel.tcl

package info (click to toggle)
nsf 2.4.0-1
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 13,208 kB
  • sloc: ansic: 32,687; tcl: 10,723; sh: 660; pascal: 176; javascript: 135; lisp: 41; makefile: 24
file content (189 lines) | stat: -rw-r--r-- 5,853 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
#
# This example is a straight translation of the OTcl Tutorial
# https://www.isi.edu/nsnam/otcl/doc/tutorial.html to NX. It serves as
# a very short intro to the basic elements of scripting with NX and
# provides a comparison study to OTcl.
#

package req nx
package req nx::test
nx::test configure -count 1

# Suppose we need to work with many bagels in our application. We
# might start by creating a Bagel class.

? {nx::Class create Bagel} ::Bagel

# We can now create bagels and keep track of them using the info
# method.

? {Bagel create abagel} ::abagel

? {abagel info class} ::Bagel

? {Bagel info instances} ::abagel

# Of course, bagels don't do much yet. They should remember whether
# they've been toasted. We can create and access an instance variable
# by defining a property for the class. All instance variables are
# per default public in the sense of C++.
? {Bagel property {toasted 0}} ""

# Since abagel was created before the definition of the property we
# have to set the default value for it using the setter method. Again,
# the info method helps us keep track of things.

? {abagel info vars} ""

? {abagel configure -toasted 0} ""

? {abagel info vars} toasted

? {abagel cget -toasted} 0

# But we really want them to begin in an untoasted state to start
# with.

? {Bagel create bagel2} ::bagel2

? {bagel2 info vars} toasted

? {bagel2 cget -toasted} 0

#
# Our bagels now remember whether they've been toasted. Let is
# recreate the first one.

? {lsort [Bagel info instances]} {::abagel ::bagel2}

? {::abagel destroy} ""

? {Bagel info instances} ::bagel2

? {Bagel create abagel} ::abagel

# Now we're ready to add a method to bagels so that we can toast
# them. Methods have an argument list and body like regular
# Tcl procs. Here's the toast method.

? {Bagel public method toast {} {
      if {[incr :toasted] > 1} then { 
        error "something's burning!"
      }
}} "::nsf::classes::Bagel::toast"

# The defined methods can be queried with info. We see as well the
# setter method for the variable toasted.

? {Bagel info methods} {toast}

# Aside from setting the toasted variable, the body of the toast
# method demonstrates how to access instance variables by using a
# leading colon in the name. 

# We invoke the toast method on bagels in the same way we use the
# info and destroy methods that were provided by the system. That
# is, there is no distinction between user and system methods.

? {abagel toast} ""
? {abagel toast} "something's burning!"

# Now we can add spreads to the bagels and start tasting them. If we
# have bagels that aren't topped, as well as bagels that are, we may
# want to make toppable bagels a separate class. Let explore
# inheritance with these two classes, starting by making a new class
# SpreadableBagel that inherits from Bagel. A SpreadableBagel has an
# property toppings which might have multiple values. Initially,
# toppings are empty.

? {nx::Class create SpreadableBagel -superclass Bagel {
    :property -incremental {toppings:0..n ""}
}} ::SpreadableBagel

? {SpreadableBagel cget -superclass} ::Bagel
? {SpreadableBagel info superclasses} ::Bagel

? {SpreadableBagel info heritage} {::Bagel ::nx::Object}

# Let's add a taste method to bagels, splitting its functionality
# between the two classes and combining it with next.

? {Bagel public method taste {} {
    if {${:toasted} == 0} then {
    return raw!
  } elseif {${:toasted} == 1} then {
    return toasty
  } else {
    return burnt!
  }
}} "::nsf::classes::Bagel::taste"

? {SpreadableBagel public method taste {} {
    set t [next]
    foreach i ${:toppings} {
       lappend t $i
    }
    return $t
}} "::nsf::classes::SpreadableBagel::taste"

? {SpreadableBagel create abagel} ::abagel

? {abagel toast} ""
? {abagel toppings add jam} jam
? {abagel toppings add m&m} "m&m jam"

? {abagel taste} "toasty m&m jam"

# Of course, along come sesame, onion, poppy, and a host of other
# bagels, requiring us to expand our scheme. We could keep track of
# flavor with an instance variable, but this may not be
# appropriate. Flavor is an innate property of the bagels, and one
# that can affect other behavior - you wouldn't put jam on an onion
# bagel, would you? Instead of making a class hierarchy, let's use
# multiple inheritance to make the flavor classes mixins that add a
# their taste independent trait to bagels or whatever other food they
# are mixed with.

? {nx::Class create Sesame {
    :public method taste {} {concat [next] "sesame"}
}} ::Sesame

? {nx::Class create Onion {
    :public method taste {} {concat [next] "onion"}
}} "::Onion"

? {nx::Class create Poppy {
    :public method taste {} {concat [next] "poppy"}
}} "::Poppy"

# Well, they don't appear to do much, but the use of next allows them
# to be freely mixed.

? {nx::Class create SesameOnionBagel -superclass SpreadableBagel -mixin {Sesame Onion}} ::SesameOnionBagel

? {SesameOnionBagel create abagel -toppings butter} "::abagel"

? {abagel taste} "raw! butter onion sesame"

# For multiple inheritance, the system determines a linear inheritance
# ordering that respects all of the local superclass orderings. You
# can examine this ordering with an info option. This ordering
# determines the method resolution, when e.g. "next" is called.

? {SesameOnionBagel info heritage} {::Sesame ::Onion ::SpreadableBagel ::Bagel ::nx::Object}

? {abagel info precedence} {::Sesame ::Onion ::SesameOnionBagel ::SpreadableBagel ::Bagel ::nx::Object}

# We can also combine our mixins with other classes, classes that need
# have nothing to do with bagels, leading to a family of chips.

? {nx::Class create Chips {
    :public method taste {} {return "crunchy"}
}} "::Chips"

? {nx::Class create OnionChips -superclass Chips -mixin Onion} ::OnionChips

? {OnionChips create abag} ::abag

? {abag taste} "crunchy onion"