[ A world of words ] naming convention, namespace, namespace pollution,
[1/15] from: rebol::meurrens::org at: 28-May-2003 11:40
Hello,
[ A world of words ]
naming convention, namespace, namespace pollution, good practises,
coding styles
+
multiple inheritance in the example
As things are going on, I feel the necessity to organize a little bit
the names I use.
I mean, as well, names for script *files*
and names for *words* used to store my values.
I did not find on the web or by reading existing scripts
something like a "convention", a "tradition"
{ tradition may be incompatible with rebolution -:) ??? }
The need arises from several reasons
--- avoid clashes, namespace pollution, etc in my own works
--- avoid clashes in a cooperative/collaborative process as permitted by REBOL
do http://rebol.my-friend.net/his-her-script.r
--- readability/documentation/sharing knowledge
--- deal with "no private/public in REBOL objects" (as for PHP, etc)
{ I allways prefix all private things with "_" (underscore) }
--- deal with "no object strong typing in REBOL" (as for PHP, etc)
--- deal with "no return type in function signature"
--- deal with "case insensitive in REBOL"
{no camelBack convention, but we may still decide to use it on a
voluntary basis}
{no ALL_UPPER_CASE convention, but we may still decide to use it on a
voluntary basis}
--- existing scripts show an extensive use of "-" (minus) but not "_"
(underscore)
Any reason ???
--- availability in the names of "special" characters such as "?" "!" "#"
that have/should have/receive a "universal conventional" meaning.
Below are some of my current ideas/practises.
Together with a short example.
But before deciding/publishing/re-inventing the wheel/etc,
I'll like to know if there exists already some "good practises". ??????????
When do you use *.r or *.reb or even *.rebol ???
(*.rip is for archives)
Do you use some other extensions ???
(a part of *.exe for Win32 executables of course)
e.g. to store images converted to REBOL binaries, etc, etc ???
as
%rebol-logo_83x31.jpg.r
Do you use prefixes for your script names ???
such as
%i-my-script.r ;;; defines a unique value : i-my-script , an interface
definition block
%o-my-script.r ;;; defines a unique value : o-my-script , an implementation
definition block
%my-script.r ;;; defines a set of values
%v-my-script.r ;;; a so-called events driven "application" using REBOL/VIEW
%c-my-script.r ;;; a so-called "application" using REBOL/CORE
my-script.exe ;;; compilation of %v-my-script.r for WIN32
Special names for files holding data ??? preferences ??? configurations ???
a part from the well known
%user.r
%preferences.r
something like ???
%my-script.ini.r
How do you define an "application" ???
How do you define a "reblet" ???
Do you have conventions to let know that a given file
is just a set of values, or is a "reblet" ??? an application ???
Do you use special conventions for naming your words ???
such as
?my-object ;;; help function
?my-object-my-value ;;; help function
my-word? ;;; returns a logic (boolean)
what about other special characters, such as "# " and "!" ???
when used as the first letter??? as the last???
Is there a consensus in the community on how/when to use them ???
Do you use something like an hungarian prefix ???
such as in the following script
{ demonstrating also so-called "multiple inheritance"
and the " interface v. body" pattern
we initially developped for JAVA in an anterior and still parallel life }
Do you use "multiple inheritance" ???
(does not replace "composition"...!)
Do you use upper/lower cases for documentation purposes ???
such as
A_NOT_SO_GOOD_PI: 3.14 ;; constant
Do you use indentation conventions
and some other coding syles ???
===
REBOL[]
;;;; in file i-browser.r ;;; just to show interface v. implementation +
show multiple inheritance
i-browser: [
?browser: function [/all][][ print "smart browser" if found? all [
?browser-run ?browser-msg-bye ] ] ;
?browser-run: does [ help browser-run ]
browser-run: function ["browse an url" u [url!]][][ browse u ] ;
default implementation
?browser-msg-bye: does [ print "browser-msg-bye: ; message displayed
when leaving the application"]
browser-msg-bye: "bye bye"
]
;;;; in file o-browser.r ;;; just for the fun; not very smart indeed
o-browser: [
browser-run: function ["browse an url" u [url!]][][
either connected? [ alert browser-msg-bye browse u ]
[ alert "you are not connected to internet" ]
]
]
;;;; in file i-pretty-script.r
i-pretty-script: [
?pretty-script: function [/all][][ print "a funny example" if found? all [
?pretty-script-run ?pretty-script-col-black ?pretty-script-col-white
] ]
; existence of ?pretty-script is also a way to test if an object "IS" a
i-pretty-script
?pretty-script-col-black: does [ print "pretty-col-black: ; black is
beautifull"]
pretty-col-black: 10.10.10 ; nearly black
?pretty-script-col-white: does [ print "pretty-col-white: ; white is
never really white"]
pretty-col-white: 245.245.245 ; nearly white
?pretty-script-run: does [ help pretty-run ]
pretty-run: function ["just try it"][][] ; dummy here ; to ovrdn
]
;;;; in file o-pretty-script.r
;;;; dependencies : i-pretty-script.r i-browser
o-pretty-script: [
pretty-col-black: does [ random 20.20.20 ] ; ovrdn as a function, just
for the fun.
_pretty-col-marc: 33.66.99 ; the blue used in this implementation
_pretty-laydef-1: [
style sty-but button 80x20 bold
_pretty-1-but-black: sty-but pretty-col-black "black" [
alert join "nearly black " face/color
]
sty-but _pretty-col-marc "home" [ browser-run
http://www.meurrens.org/ ]
sty-but pretty-col-white "close" [ unview ]
sty-but _pretty-col-marc "quit" [ quit ]
]
pretty-run: function ["just try it"][][
view layout _pretty-laydef-1
]
]
;;;; in my applic file
random/seed now
my-specific: [
pretty-col-black: random 255.0.0 ; black becomes red
pretty-col-white: request-color/color 233.234.235 ; let the user
choices the white
browser-msg-bye: {Ce n'est qu'un "Au Revoir", mes fr=E8res}
?: does [ print "===" ?browser/all print "===" ?pretty-script/all
print "===" ]
]
my-obj: make make make make make object! ; 5 make's expect 5 def's :
i-pretty-script
i-browser
o-pretty-script
o-browser
my-specific
; open the console...
my-obj/?
; do some job...
my-obj/pretty-run
my-obj/browser-run http://www.rebol.com/
====
As you see, there are many questions and I certainly forgot a lot...
I'll appreciate your feedback.
Regards
</marc>
Prof. Ir Marc Meurrens, Brussels (be)
TEL: +32 (0)2 537 2812
FAX: +32 (0)2 537 7645
EMAIL: [marc--meurrens--org]
URL: http://www.meurrens.org/
REB: http://rebol.mksa.net/
PGPKEY: http://www.meurrens.org/pgp/
Please don't mail me attached files, instead, use my 'exchange area' :
EXCHANGE AREA: http://www.meurrens.org/exchange/
(HTTP/FTP upload/download of temporary/persistent files)
[2/15] from: gchiu:compkarori at: 28-May-2003 23:16
Re: [ A world of words ] naming convention, namespace, namespace pollut
On Wed, 28 May 2003 11:40:31 +0200
Marc Meurrens <[rebol--meurrens--org]> wrote:
>As you see, there are many questions and I certainly
>forgot a lot...
>
>I'll appreciate your feedback.
Marc,
Please read the official style guide:
http://www.rebol.com/docs/core23/rebolcore-5.html#sect5.
which may answer some of your questions
--
Graham Chiu
http://www.compkarori.com/vanilla/
Rebol Encyclopaedia Project
[3/15] from: ptretter:charter at: 28-May-2003 7:34
I would just add that I really don't think that anything is needed beyond
the style guide. I think the freedom of expression within the code is not a
problem. Most REBOLers can distinguish the code without need of certain
conventions. REBOL should stay easy to learn like it was for me when I
started out.
Paul Tretter
----- Original Message -----
From: "Graham Chiu" <[gchiu--compkarori--co--nz]>
To: <[rebol-list--rebol--com]>
Sent: Wednesday, May 28, 2003 6:16 AM
Subject: [REBOL] Re: [ A world of words ] naming convention, namespace,
namespace pollution, good practises, coding styles
[4/15] from: nitsch-lists:netcologne at: 28-May-2003 14:41
Marc Meurrens wrote:
> Hello,
> [ A world of words ]
<<quoted lines omitted: 9>>
> something like a "convention", a "tradition"
> { tradition may be incompatible with rebolution -:) ??? }
http://www.rebol.com/docs/core23/rebolcore-5.html
Eventually get an IOS-account, there are some original rt-style-apps.
>
> The need arises from several reasons
> --- avoid clashes, namespace pollution, etc in my own works
> --- avoid clashes in a cooperative/collaborative process as permitted
> by REBOL
> do http://rebol.my-friend.net/his-her-script.r
my-module: context[ .. ]
you have to take care you made all words local.
Either by function-locals or by having them as set-words in the top-level.
means, here 'a is local, but 'b is global. :
ctx: context[ a: 123 do [b: 234] ]
because the context-builder did not look in the inner block.
a good way to check if you made something global:
query/clear system/words do %script.r probe query system/words
> --- readability/documentation/sharing knowledge
> --- deal with "no private/public in REBOL objects" (as for PHP, etc)
> { I allways prefix all private things with "_" (underscore) }
with series, 'find and all the inbuild stuff i rarely need a lot of fields.
public/private or deep object-hierarchies are waste of time with typical
script-sizes IMHO.
stuff like
files: [%file1.r as-text %file2.r as-binary]
foreach [file mode][either 'as-text = mode[..][..] ]
saves some declarations :)
> --- deal with "no object strong typing in REBOL" (as for PHP, etc)
> --- deal with "no return type in function signature"
keep a console open. often you can try the function and look at its result.
rebol needs not much initialisation, so trying out is often as fast as
switching to help-window.
> --- deal with "case insensitive in REBOL"
> {no camelBack convention, but we may still decide to use it on a
> voluntary basis}
> {no ALL_UPPER_CASE convention, but we may still decide to use it
> on a voluntary basis}
personally, dealing with camelBack is harder ;)
> --- existing scripts show an extensive use of "-" (minus) but not "_"
> (underscore)
> Any reason ???
rebol does it. and it saves shift-keys :)
> --- availability in the names of "special" characters such as "?" "!" "#"
> that have/should have/receive a "universal conventional" meaning.
length? something.
inbuild datatypes are marked integer!
> Below are some of my current ideas/practises.
> Together with a short example.
<<quoted lines omitted: 8>>
> as
> %rebol-logo_83x31.jpg.r
*.r for files which can be loaded, *.txt for texts.
RT uses *.rcb for rebol-compressed binary (~zip) and some other extensions.
> Do you use prefixes for your script names ???
> such as
<<quoted lines omitted: 7>>
> %c-my-script.r ;;; a so-called "application" using REBOL/CORE
> my-script.exe ;;; compilation of %v-my-script.r for WIN32
with lots of files i prefer %module-name-type.r . file-requestors sort
by module, and *-type.r selects the file-type.
IOS prefers simple names and subdirectories.
> Special names for files holding data ??? preferences ???
> configurations ???
<<quoted lines omitted: 3>>
> something like ???
> %my-script.ini.r
on IOS a lot %prefs.r . And variable-style filenames.
>
> How do you define an "application" ???
> How do you define a "reblet" ???
> Do you have conventions to let know that a given file
> is just a set of values, or is a "reblet" ??? an application ???
reblets have larger headers :)
I use "reblet" to interface a server and demos on rebsites.
application
means standalone.
> Do you use special conventions for naming your words ???
> such as
> ?my-object ;;; help function
> ?my-object-my-value ;;; help function
> my-word? ;;; returns a logic (boolean)
my-word?
for others i would use a word instead of "?", about-my-object or something.
btw, console has tab-completion, so abo^tab is not to much typing ;)
And help with a string shows all words with the string inside, like help
read
> what about other special characters, such as "# " and "!" ???
> when used as the first letter??? as the last???
> Is there a consensus in the community on how/when to use them ???
i guess consensus is, not as first letter.
> Do you use something like an hungarian prefix ???
> such as in the following script
when using /view, i often have the same name for a variable and its face,
so i call the face f-variable-name. sometimes i use hungarian postfix
(variable-face).
> { demonstrating also so-called "multiple inheritance"
> and the " interface v. body" pattern
> we initially developped for JAVA in an anterior and still parallel life }
>
> Do you use "multiple inheritance" ???
> (does not replace "composition"...!)
not conscious.
> Do you use upper/lower cases for documentation purposes ???
> such as
> A_NOT_SO_GOOD_PI: 3.14 ;; constant
loong ago there was the preprocessor, and it was handy and smart and did
not know nothing about
lexical scopes. So peoples wrote BE_WARNED in very big letters.
Also it says: this is an integer which wants to be an enumeration.
here we use
if 'as-text = mode []
no need to bring the integer-step in, no need for warning.
So with Rebol, why? :)
> Do you use indentation conventions
> and some other coding syles ???
%clean-script.r, open brackets are the last on the line, closing
brackets have their own line.
'any / 'all instead of 'if, when possible.
func[a /local b] instead of function[a][b]
[5/15] from: greggirwin:mindspring at: 28-May-2003 12:20
Hi Marc,
Lots of good questions here. Others have given you good advice, so
I'll just add a few opinions from my perspective. Bear in mind that
I've only been REBOLing for a couple years; I'm still adjusting my
mindset and still trying new things.
MM> --- avoid clashes, namespace pollution, etc in my own works
Yes, Meyer's thoughts on Linnaean naming conventions are very
applicable to REBOL I think.
MM> --- readability/documentation/sharing knowledge
This is most important of all to me.
MM> --- deal with "no private/public in REBOL objects" (as for PHP, etc)
MM> { I allways prefix all private things with "_" (underscore) }
You *can* actually create private words, with a USE block, but I
haven't used this technique much myself in real applications.
o: make object! [
get-a: set-a:
get-b: set-b:
none
use [_a _b] [
_a: _b: none
get-a: does [_a]
set-a: func [value] [_a: value]
get-b: does [_b]
set-b: func [value] [_b: value]
]
]
It adds a lot of code compared to:
o: make object! [a: b: none]
I keep thinking that I'll use it for larger things, or where I
explicitly want to protect private items, but only time will tell.
MM> --- deal with "case insensitive in REBOL"
MM> {no camelBack convention, but we may still decide to use it on a
MM> voluntary basis}
MM> {no ALL_UPPER_CASE convention, but we may still decide to use it on a
MM> voluntary basis}
I go for readability first. I came from a VB - which is case
insensitive - and I've *never* understood the appeal of case sensitive
languages. I'm particularly confused by the Smalltalk/Ruby rule about
the *first* letter's case defining the scope. Very strange to me. In
Ruby it's a language rule, in Smalltalk it's just a convention IIRC.
In any case, I've moved away from CamelBack, using dashes to separate
words in REBOL.
MM> --- existing scripts show an extensive use of "-" (minus) but not "_"
MM> (underscore)
MM> Any reason ???
I think it's easier to type and more natural looking. Other languages
don't allow it or they would probably have used it too. :)
MM> When do you use *.r or *.reb or even *.rebol ???
.r for REBOL files, .txt for most other things (using make-doc
formatting for most things). I'm still playing with what to do about
files that are really data, compressed or otherwise, but are also
valid REBOL code. It's fuzzy sometimes so it's hard to say if
something is treated more like data than code or vice-versa.
MM> Do you use prefixes for your script names ???
No, but I've never done that. Under VB I used a modified Hungarian
notation, but I use *very* little of it under REBOL; just for words
that refer to VID faces at this point, and still playing with it.
MM> Special names for files holding data ??? preferences ??? configurations ???
MM> a part from the well known
MM> %user.r
MM> %preferences.r
MM> something like ???
MM> %my-script.ini.r
I avoid names with multiple dots in them (e.g. xxx.ini.r) because you
never know when something might get tripped up over it. For some
archive versions of files, I've included the version in the file name
and, while I like using dots in that case, I haven't decided if it's
worth the risk.
MM> How do you define an "application" ???
MM> How do you define a "reblet" ???
MM> Do you have conventions to let know that a given file
MM> is just a set of values, or is a "reblet" ??? an application ???
I'll often put a "tail" on file names that tells me what they are.
E.g.
my-app.r
my-app-lib.r
my-app-test.r
my-app-defs.r
Other types of files get a prefix. E.g.
build-my-app.r
All my Windows library modules (for API defs and interfaces) start
with "win-".
Ultimately, I try to make the names read well, so they match how I
would say them.
MM> Do you use special conventions for naming your words ???
...
MM> what about other special characters, such as "# " and "!" ???
MM> when used as the first letter??? as the last???
MM> Is there a consensus in the community on how/when to use them ???
There is no consensus AFAIK.
I use a trailing "?" for logic values.
You can't use "#".
I use * or ! sometimes, to denote a special word that is, for example, a
(duplicate) reference to a value that gets modified. I usually prepend
!, so it isn't confused with datatype values.
MM> Do you use something like an hungarian prefix ???
Not much, as I said above. REBOL is meant to be readable, and
Hungarian isn't. :) There are places I'm still playing with it, like
using "ctx" for objects/contexts which may not be referenced directly
in much code.
MM> { demonstrating also so-called "multiple inheritance"
MM> and the " interface v. body" pattern
MM> we initially developped for JAVA in an anterior and still parallel life }
...
MM> Do you use "multiple inheritance" ???
MM> (does not replace "composition"...!)
I've only toyed with the concept in REBOL. It's a different mindset
because it doesn't have to be set at design time. You could easily
aggregate them at runtime. Makes for interesting possibilities.
MM> Do you use upper/lower cases for documentation purposes ???
MM> such as
MM> A_NOT_SO_GOOD_PI: 3.14 ;; constant
I've gotten away from that convention as a general rule. I tend to
treat it like underlined text now. It's only appropriate occasionally,
and it's disruptive when you're reading.
-- Gregg
[6/15] from: greggirwin::mindspring::com at: 28-May-2003 15:47
Hi Marc,
MM> --- availability in the names of "special" characters such as "?" "!" "#"
I forgot another thing I use them for! If I have a code template that
I want to LOAD, and it contains replaceable parameters, I will
use those special characters to give them names that stand out, but
still allow the code to be LOADed by REBOL. E.g.
display-item: func [
{Load the screen with the data from the given item.}
item
][
!!!display-item!!!
id-list/picked: append clear id-list/picked item/id
show main-lay
]
Sometimes it's still easier just to use strings, but having lexically
correct data can be useful at times.
-- Gregg
[7/15] from: rebol:meurrens at: 2-Jun-2003 11:19
Hello Greg,
At 12:20 28/05/2003 -0600, you wrote:
>You *can* actually create private words, with a USE block, but I
>haven't used this technique much myself in real applications.
<<quoted lines omitted: 10>>
> ]
> ]
The miscellaneous methods proposed on this list
(and, to me, by private mail from other rebollers)
to create PRIVATE things ....
;;;;;;;;;;;;;;;;;;;;
REBOL []
use [ priv1 ] [ o1: make object! [ priv1: 1 =pri: does [ priv1 ] ] ] ;;;
priv1 remains a *PUBLIC* INSTANCE WORD
use [ priv2 ] [ priv2: 2 o2: make object! [ =pri: does [ priv2 ] pri=:
func[a][priv2: a] ] ] ;;; priv2 is a PRIVATE STATIC WORD
o3: make object! [ =pri: none use [priv3] [ priv3: 3 =pri: does [ priv3 ]
] ] ;;; priv3 is a PRIVATE STATIC WORD
o4: make object! [ a:41 use [] [ b: 42 ] ] ;;; a INSTANCE WORD ;;; b
GLOBAL WORD
o22: make o2 []
;;;;;;;;;;;;;;;;;;;;;;;;
... only apply for so-called "static variables"
{
; =pri ; pronounce "get pri"
; pri= ; pronounce "set pri"
}
Just run the above mini script and, then, try :
priv1 ; error
priv2 ; error
priv3 ; error
o1/priv1 ; 1 ; !!!!!!!!!!!!! PUBLIC
o2/priv2 ; error
o22/priv2 ; error
o3/priv3 ; error
o1/=pri ; 1
o2/=pri ; 2
o22/=pri ; 2
o3/=pri ; 3
o22/pri= 22 ; 22
o22/=pri ; 22
o2/=pri ; 22 ; !!!!!!!!!!!! STATIC
Of course, it does not make difference as far as you only create underived
singletons (o1, o3)
(objects with just ONE instance).
But in ordinary situations (o2, o22, ...), it means that,
AFAIK (????? I hope I am wrong...),
there is no way to create PRIVATE INSTANCE WORDS
:-(
My own convention is to prefix their name with an "underscore"
and to destroy with energy any script that would contain
a "/" followed by a "_"
Something very easy to detect automatically :-)
HTH
</marc>
>-- Gregg
Prof. Ir Marc Meurrens, Brussels (be)
TEL: +32 (0)2 537 2812
FAX: +32 (0)2 537 7645
EMAIL: [marc--meurrens--org]
URL: http://www.meurrens.org/
REB: http://rebol.mksa.net/
PGPKEY: http://www.meurrens.org/pgp/
Please don't mail me attached files, instead, use my 'exchange area' :
EXCHANGE AREA: http://www.meurrens.org/exchange/
(HTTP/FTP upload/download of temporary/persistent files)
[8/15] from: nitsch-lists::netcologne::de at: 2-Jun-2003 14:04
Re: [ A world of words ] naming convention, namespace, namespace pollu
Marc, why do you need privates?
protection against malicious scripts is hard, because functions do not
clear their arguments after call.
>> context[ _pri: 123 set 'pri does[_pri]]
>> pri
== 123
>> second :pri ; the function-body
== [_pri]
>> get first second :pri ; the word in the body references the hidden '_pri
== 123
for informal privates a convention should do. real protection makes
debugging harder.
-Volker
Marc Meurrens wrote:
[9/15] from: greggirwin:mindspring at: 3-Jun-2003 10:02
Hi Volker,
VN> Marc, why do you need privates?
...
VN> for informal privates a convention should do. real protection makes
VN> debugging harder.
A convention is good. As a lot of us know from working with VID, you
don't have any idea what is supposed to be private, or what the "true"
public interfaces are in many cases.
Also, while I agree that private data can make debugging harder, it
can also be said that the lack of a protection mechanism can also make
debugging harder because there is no way to guarantee encapsulation,
which means any piece of code can change things so you can't rule
anything out.
In any case, I think REBOL gives us the tools we need to do things in
lots of different ways. I went through much the same process Marc is
when I found REBOL (trying to find ways to do things I've done in
other languages). Now I don't try to make REBOL work like other
languages, I try to look at how to design and build things in the
context of how REBOL works.
-- Gregg
[10/15] from: greggirwin:mindspring at: 3-Jun-2003 9:56
Hi Marc,
MM> But in ordinary situations (o2, o22, ...), it means that,
MM> AFAIK (????? I hope I am wrong...),
MM> there is no way to create PRIVATE INSTANCE WORDS
I'm not sure of what distinction you want to make between private
*instance* words and private *static* words, as shown in your o3
example. I modded it here to provide a set accessor function.
o3: make object! [
=pri: pri=: none
use [priv3] [
priv3: 3
=pri: does [ priv3 ]
pri=: func [a] [priv3: a]
]
] ;;; priv3 is a PRIVATE STATIC WORD
>> o33: make o3 []
>> o3/=pri
== 3
>> o3/pri=: 33
== 33
>> o3/=pri
== 3
>> o33/=pri
== 3
I would hazard a guess that you can acheive what you want (once we
know exactly what that is).
MM> My own convention is to prefix their name with an "underscore"
MM> and to destroy with energy any script that would contain
MM> a "/" followed by a "_"
MM> Something very easy to detect automatically :-)
I've done the same thing myself in a number of places. Of course, then
I found one place where I wanted to actually use a leading underscore
with words in an object, so I'm still considering what the best
approach or convention is for this kind of thing.
-- Gregg
[11/15] from: rebol:meurrens at: 4-Jun-2003 0:54
Re: [ A world of words ] naming convention, namespace, namespace pollut
Hi Gregg,
Thank you for your interest in this matter.
I was surprised (and very happy) by your result.
Unfortunately there is a small mistyping (the ":")
>> o3/pri=: 33
>== 33
You did not use the "set method" ; you just replaced it by 33 .... :-(
Anyway, here is the example completely rewritten
for all the readers who did not follow this thread
since the beginning.
This makes clear, for those not aware of our OO vocabulary, what we mean
by "static"
and by "instance".
A more pedagogical example (the "tank") still come later in this message
together with "what I want".
REBOL [ ]
use [ y z ]
[
z: 3 ; PRIVATE STATIC WORD (thanks 'use)
obj: make object! [
=z: does [ z ]
z=: func [ a ] [ z: a ]
=x: x=: none
use [ x ]
[
x: 1 ; PRIVATE STATIC WORD (not instance)
=x: does [ x ]
x=: func [ a ] [ x: a ]
]
y: 2 ; PUBLIC INSTANCE WORD (despite 'use)
=y: does [ y ]
y=: func [ a ] [ y: a ]
w: 4 ; PUBLIC INSTANCE WORD
=w: does [ w ]
w=: func [ a ] [ w: a ]
]
]
other: make obj [ ]; another instance
; x is PRIVATE : obj/x ===> error
; x is STATIC ...
obj/x= 11
other/=x ; ===> 11
; y is PUBLIC :
obj/y ; ===> 2
; y is INSTANCE ...
obj/y= 22
other/=y ; ===> 2 (unchanged)
; z is PRIVATE : obj/z ===> error
; z is STATIC ...
obj/z= 33
other/=z ; ===> 33
I would hazard a guess that you can acheive what you want (once we
>know exactly what that is).
This would be nice.
Let us discuss of the "tank" example.
It's a very simple example I often use to illustrate OO,
and how OO can be implemented in some language.
If you, or another reboller, has a solution to this "school case"
this would be marvellous....
;;;;;;;;;;;;; WHAT I WANT... THE "TANK" EXAMPLE
use [ _capacity ] [
_capacity: 100 ; max number of gallons in any tank ;;; "STATIC"
tank1: make object! [
_content: 0 ; current nr of gallons in this very tank ;;;
each "INSTANCE" has a different content
content+: func [ add ] [ _content: max 0 min _capacity
_content + max 0 add ]
content-: func [ sub ] [ _content: max 0 min _capacity
_content - max 0 sub ]
=content: does [ _content ]
=capacity: does [ _capacity ]
]
]
tank2: make tank1 [ ] ; two different instances
tank1/content+ 50 ; add 50 gallons in tank 1
tank2/content+ 80 ; add 80 in tank 2
tank2/content- 20 ; substract 20 from tank 2
tank1/content+ 999 ; try (!!!!!) to add 999 in tank 1 (much will go on the
floor...)
tank1/content- 5 ; substract 5 from tank 1
tank1/=content ; ===> 95 (try with your own car: 0 + 50 + 999 - 5 ===> 95 !!!)
tank2/=content ; ===> 60 ( 0 + 80 - 20 )
;;;;;;;;;;;;;;;; I WANT TO AVOID THAT WE MAY WRITE THIS HORRIBLE CODE:
cash: -500 ; i now allow negative values for cash due to my new credit policy
; .... and 425 lines below...
price: 30 ; price of gas in $ per gallon
; .... and 212 lines below...
a: cash / price ; use all our money to buy gas. how much gallons may we
receive?
; ... and 723 lines below...
tank1/_content: a ; now the tank holds a negative number of gallons...
; later on, we'll use tank1/_content or tank1/=content
; to compute a negative distance...
; etc, etc... and somewhere else we'll crash our car on a wall... !!!
;;;;;;;;;; BY AVOIDING A DIRECT ACCESS TO _content == BY ENCAPSULATING _content
(for those who are new to OO concepts/vocabulary, the '_content is
encapsulated
with appropriate methods; mind that there is no "set" method and that the
increase
and "decrease" methods carefully check argument and result)
>MM> My own convention is to prefix their name with an "underscore"
>MM> and to destroy with energy any script that would contain
<<quoted lines omitted: 4>>
>with words in an object, so I'm still considering what the best
>approach or convention is for this kind of thing.
;;;;; THE ONLY WAY I FOUND FOR INSTANCE VARIABLES IN REBOL
;;;;; IS THE CONVENTION "private begins with _"
;;;;; (that I also use in other languages)
;;;;; and then to detect the presence of "/" followed by "_" in scripts.
;;;;; WHY ? NOT AGAINST MALICIOUS SCRIPTS,
;;;;; BUT JUST TO PRODUCE ROBUST/READABLE/REUSABLE CODE
; a "malicious" script may decide anyway that it will not respect the
convention
; a "malicious" script may anyway use 'set and access to everything,
; even things "protected" by 'use
; and even without using "/" followed by "_"
;; example: give a negative value to the _capacity :
>> probe tank1
>> make tank1 [ set first second :=capacity -999 ]
>> tank2/=capacity
== -999
See also Volker's "malicious" example in message 29138 of this thread.
Regards,
</marc>
>-- Gregg
>
Prof. Ir Marc Meurrens, Brussels (be)
TEL: +32 (0)2 537 2812
FAX: +32 (0)2 537 7645
EMAIL: [marc--meurrens--org]
URL: http://www.meurrens.org/
REB: http://rebol.mksa.net/
PGPKEY: http://www.meurrens.org/pgp/
Please don't mail me attached files, instead, use my 'exchange area' :
EXCHANGE AREA: http://www.meurrens.org/exchange/
(HTTP/FTP upload/download of temporary/persistent files)
[12/15] from: dockimbel:free at: 4-Jun-2003 11:06
Re: [ A world of words ] naming convention, namespace, namespace poll
Hi Marc,
En réponse à Marc Meurrens <[rebol--meurrens--org]>:
[...]
> ;;;;;;;;;;;;; WHAT I WANT... THE "TANK" EXAMPLE
> use [ _capacity ] [
<<quoted lines omitted: 11>>
> ]
> ]
[...]
If you use private contexts, keep in mind that you may loose some REBOL
important features like :
- reflection :
>> first tank1 ; get all words defined in object tank1
== [self _content content+ content- =content =capacity]
You cannot see '_capacity anymore. A function using reflection to process
your object will miss this word.
- serialization :
>> tank1: load mold tank1
>> tank1/=capacity
>> _capacity
** Script Error: _capacity has no value
** Near: _capacity
Same issue when saving then reloading your object with save & load or when
sending it over a tcp connection.
HTH,
-DocKimbel
[13/15] from: greggirwin:mindspring at: 4-Jun-2003 12:33
Hi Doc,
dff> If you use private contexts, keep in mind that you may loose some REBOL
dff> important features like :
dff> - reflection :
dff> - serialization :
Excellent points Doc!
-- Gregg
[14/15] 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]
[15/15] from: nitsch-lists:netcologne at: 5-Jun-2003 1:04
Hi Marc, Gregg,
My favorite style-example is vid.
Its large, but lots smaller than comparable gui-toolkits.
And Carl tries to avoid accessor-functions there.
trying vid-style, i would use an interface like
tank/duration: 00:00:05
tank/rate: 5 ; liters
flow tank
if one wants really to access tank/content directly, in vid he could.
some times usefull, most time why?
-Volker
Gregg Irwin wrote:
>Hi Marc,
>MM> Unfortunately there is a small mistyping (the ":")
<<quoted lines omitted: 104>>
> 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"
<<quoted lines omitted: 7>>
> available: tanks/:id*/content
> tanks/:id*/content: tanks/:id*/content - min amount*
available
Notes
- Quoted lines have been omitted from some messages.
View the message alone to see the lines that have been omitted