Mailing List Archive: 49091 messages
  • Home
  • Script library
  • AltME Archive
  • Mailing list
  • Articles Index
  • Site search

[REBOL] Re: [ A world of words ] naming convention, namespace, namespace poll

From: greggirwin::mindspring::com at: 4-Jun-2003 14:49

Hi Marc, MM> Unfortunately there is a small mistyping (the ":") Thanks for catching that! I'm not always as careful as I should be when responding to ML items; I go too fast and think too little. :) Thanks also for your detailed response. Now I can see clearly the issue we're up against, with the USE context being shared between instances. I thought about it for a little bit, and didn't come up with any brilliant solutions. While it might be possible to cook one up, it would likely obscure the main point and cause confusion if used as a teaching tool. So, I started on my real work for the day, but it nagged me, and then an idea began to grow in my mind. Given that REBOLs approach to OO concepts is different from the norm, should we really try to force fit standard examples into it? Maybe not. If students need to learn Java, C++, or .NET rules about how OO works in those enivirons, how valuable is it to see examples in REBOL. In other words, the OO concepts can be pure, but the implementations are not. In that light, how valuable is it to be able to see those concepts in action? I place a high value on that kind of thing myself, but there is a mismatch. If you create an articfical environment for demonstrating OO concepts, it doesn't really matter how it works behind the scenes, or if the language used is useful for other things (i.e. in the real world) versus being used *only* to explain and demonstrate OO concepts. What I'm talking about, of course, is building a dialect in REBOL which would be used to explain and demonstrate OO concepts as clearly as possible, without any particular regard for practicality. But I digress... MM> ;;;;;;;;;;;;; WHAT I WANT... THE "TANK" EXAMPLE Rather than taking a traditional approach which, as I said, would probably end up being less than attractive, I decided to look at it in a different way; a REBOLish way. What we want, is to use abstraction and information hiding to our advantage. Where REBOL differs is how strict it is about enforcing some of these things. In your scenario of the horrible code we *may* write, REBOL doesn't offer us much protection in how it implements OOP concepts. So how do we elegantly provide encapsulation and abstraction? How about with a dialect? Using your comments as a guide, I put together a dialect based approach to the tank problem. I started out simple, but kept getting ideas and decided to play with them a bit. (code at end of message) This approach doesn't solve the problem of completely preventing people from doing bad things if they have access to the code and data structures used internally, but it does show that you can provide a public interface that only allows certain things to be done. The way results are returned is...different. As I worked, I wanted a way to see the results of a command in context, then I started thinking about messaging in a remote or asynchronus enivronment, and *real* messaging as opposed to just RPC. I'll have to play with the idea more, and think about how the grammar needs to be bi-directional; that is, the client side may want to parse the response it gets. In any case, let me know what you think. I have to go do some real work now! :\ -- Gregg ; Code below. Watch for wrap! REBOL [] tank: make object! [content: 0 capacity: 100] tank-context: make object! [ tanks: copy [] results: copy [] ; This FORMs all results, so numeric result may not want to use it. add-result: func [item] [append results reduce [reform item]] ; Dialect Rules rules: context [ available: none ; Parsed data (using a trailing * to denote them) id*: amount*: word*: none gallons: ['gallons | 'gallon] tank-id: [ opt 'tank set id* [issue! | integer!] (id*: to issue! id*) ] make-tank: [ 'make tank-id opt [ opt ['with 'a] 'capacity opt 'of set amount* integer! opt gallons ] ( either find/skip tanks id* 2 [ add-result ["tank" id* "already exists"] ][ append tanks reduce [ id* make tank compose [ capacity: (either amount* [amount*][100]) ] ] add-result ["tank" id* "added"] ] ) ] destroy-tank: [ 'destroy tank-id ( either find/skip tanks id* 2 [ remove/part find tanks id* 2 add-result ["tank" id* "destroyed"] ][ add-result [ "tank" id* "didn't exist, so was not destroyed" ] ] ) ] add: [ 'add set amount* integer! opt gallons ['in | 'to] tank-id ( available: tanks/:id*/capacity - tanks/:id*/content tanks/:id*/content: tanks/:id*/content + min amount* available add-result [ "Tank" id* "now contains" tanks/:id*/content "gallons" ] ) ] subtract: [ ; 'remove might be a better word than 'subtract 'subtract set amount* integer! opt gallons 'from tank-id ( available: tanks/:id*/content tanks/:id*/content: tanks/:id*/content - min amount* available add-result [ "Tank" id* "now contains" tanks/:id*/content "gallons" ] ) ] get-value: [ opt 'get tank-id set word* word! ;(add-result tanks/:id*/:word*) ( add-result switch/default word* [ content [[ "tank" id* "contained" tanks/:id*/:word* "gallons" "at" now/precise ]] capacity [[ "tank" id* "can contain a maximum of" tanks/:id*/:word* "gallons" ]] ][ ["Tank" id* "doesn't have a" mold form word* "value"] ] ) ] main: [ some [ make-tank | destroy-tank | add | subtract | get-value ] to end ] ] ; End of dialect rules set 'tank-manager func [command [block!] /notify fn [function!]] [ clear results if not parse command rules/main [ add-result ["command" mold command "failed"] ] if notify [fn results] results ] ] cbk-fn: func [ "Callback function for tank-manager." results ] [ print mold results ] tc: :tank-context ; just a lazy shortcut for console fiddling tank-cmd: func [command [block!]] [ tank-manager/notify command :cbk-fn ] tank-cmd [make tank #1] tank-cmd [make tank #2] tank-cmd [make tank #3 capacity 200] tank-cmd [make tank 4 with a capacity of 500 gallons] tank-cmd [make #4 with a capacity of 500 gallons] tank-cmd [make #5 capacity of 500 gallons] print "" tank-cmd [destroy tank 4] tank-cmd [destroy tank #4] tank-cmd [desotry tank #5] tank-cmd [destroy tank 5] tank-cmd [destroy tank #3] print "" tank-cmd [add 50 gallons to tank 1] tank-cmd [add 80 in tank 2] tank-cmd [subtract 20 from tank 2] tank-cmd [add 999 to #1] tank-cmd [subtract 5 gallons from tank 1] tank-cmd [ ; two commands at once subtract 5 gallons from tank 1 add 25 gallons to #2 ] ;tank-cmd [subtract 105 gallons from tank 1] print "" tank-cmd [#1 content] tank-cmd [get #2 capacity tank 2 content] ; two commands at once tank-cmd [get #1 material]