Path: news.daimi.aau.dk!news-b.uni-c.dk!news.uni-c.dk!nntp-oslo.UNINETT.no!nntp-trd.UNINETT.no!nntp.uio.no!www.nntp.primenet.com!nntp.primenet.com!enews.sgi.com!news.mathworks.com!newsfeed.internetmci.com!in3.uu.net!comp.vuw.ac.nz!canterbury.ac.nz!usenet From: kasper@rakau.cosc.canterbury.ac.nz (Kasper Osterbye) Newsgroups: comp.lang.beta Subject: Initialization in BETA Date: 14 Oct 1996 00:22:05 GMT Organization: University of Canterbury Lines: 220 Distribution: world Message-ID: NNTP-Posting-Host: 132.181.12.84 Hi All, I have been experimenting with initialization in BETA. And I wanted to share some of my experiences, and hear what you have to say. I have often been annoyed that I have to declare an object static, and then I must also initialize it, I feel that it takes away some of the elegance of static objects. I have now been working on a discrete event simulation framework for BETA, and thought it would be an interesting thing to try to do a framework where you had an object initialization mechanism that was used throughout the system. Here is what I have done, and some situations where I find that it gives some quite interesting effects. First I have made a pattern "AutoInit", which will call "init" when instantiated. This builds on a special property of repititions. AutoInit: (# dummy: [(# do init exit 0 #)] @integer; init:< Object; do INNER #) the size of a repetition is computed when the object is *instantiated*, and here the we call the virtual procedure init as a side effect of that. I believe that even though this is obscure, it is part of the normal semantics of the language. I can now use AutoInit as in (# Foo : AutoInit (# a,b : @integer; init::<(# do (10,20) -> (a,b); INNER #); #); X : @Foo; Y : ^Foo; do X.a -> putInt; (* a is 10 at this point *) &Foo[] -> Y; Y.b -> putInt; (* Y.b is 20 *); &Foo(# init::(# do 50->a #) #)[] -> Y[]; Y.a -> putInt; (* Y.a is 50 here #) #) If is is not possible to prefix Foo with AutoInit, because Foo should be prefixed with something else, one can do Foo : SomeThing (# a,b : @integer; initializer : @AutoInit(# init::(# do this(Foo).init #) #); init :< (# do (10,20) -> (a,b); INNER #) #); Not quite as nice, but it works. I generally try to put the virtual init as hight up in the hierarchy as possible, that way I do not have to worry about it again. Now for a number of examples where I have used initialization on a grander scale. In one situation I needed to choose between a number of different actions depending on quite elaborate tests. This can be done using an if-construct, but is becomes large and ugly very fast. Instead I made a "RuleSet" abstraction which allows me to write: MyRules : @RuleSet (# x,y,z : @ integer; rule1:@Rule (# test::(# do 2*x-y < z -> value#); action::(# do ... #); #); rule2:@Rule (# test::(# do other code depending on x,y and z#); action::(# do ... #); #); rule3:@Rule (# test::(# do ... #); action::(# do ... #); #); rule4:@Rule (# test::(# do ... #); action::(# do ... #); #) enter (x,y,z) #); which can be used as do (123,932,18) -> MyRules The effect is that the first declared rule (rule1 through rule4), whose test pattern return true will have its action part evaluated. This is done as RuleSet: AutoInit (# allRules: @List(# element::Rule #); init::< (# do allRules.init #); (* THE ABOVE IS WRONG, SEE WARNING LATER *) Rule: AutoInit (# init::<(# do this(Rule)[] -> allRules.append; INNER #); test: v; nextValue + 1 -> nextValue #); exit v #); #); This can then be used as Color: @Enumeration (# red, green, blue, yellow, white, black :@Value #); We then have Color.red etc. If one need the values to start from say 1000, we can do Hundred :@Enumeration (# init::(# do 101 -> nextValue #); andOne, andTwo, andThree, andFour : @value #) which allow us to have Hundred.andTwo WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING Now, you must be very carefull when initializing objects. Especially I have learned that you should take care when you try to assign values to instances of virtual patterns. The followin is an example that will NOT work: DONOT : AutoInit (# init::<(# do 7 -> X.a #); X : @Foo; Foo :< (# a,b : @integer; bar :< (# enter a do inner #); #) #); UUPS: @DONOT (# Foo ::< (# bar ::< (# do 45 -> b #)#) #) The problem is that when the auto init of UUPS (inherited from DONOT) is called, X has not been assigned an object yet. Hence, X is NONE in the expression '7 -> X.a' (Yes, a static reference CAN be NONE). This is not as obscure as it might sound, it is a actual problem if you try to initialize most colections. Thus in the ruleset example RuleSet: AutoInit (# allRules: @List(# element::Rule #); init::< (# do allRules.init #); you run into this problem because of the internal representation of List, and I have had the problem with all the collections. To solve it, I will normally do: RuleSet: AutoInit (# RuleList: List(# element::Rule #); allRules: ^RuleList; init::< (# do &RuleList[] -> allRules[]; allRules.init #); It is more elaborate, but it is well encapsulated, and does not change how to use the ruleset. Anyway, I hope that this can prove useful to others and encurage you all to experiement with autoinit. I am most interested in hearing any comments and suggestions regarding this. Happy hacking, Kasper