objects: overhead, private data, naming conventions
[1/4] from: greggirwin::starband::net at: 18-Sep-2001 11:27
Hi All,
I know it's often futile to ask for consensus among developers so consider
this a "solicitation for opinions". :)
For the sake of discussion, let's use something simple like rgb-color. In a
small app, dealing directly with tuples is manageable. Coming from a world
where projects are sometimes large, I'm accustomed to using as much
abstraction as possible to ease long term maintenance. This would mean
creating an rgb-color class. Like everything else in life and software
development, there's not always a black and white answer. If I asked "Should
I use objects?", the answer would probably be "sometimes". There will be
times when I don't need them and times when I do. I just need to figure out
what my own rules are about when to use them. If anyone else has guidelines
that they use, I'd love to hear what they are.
I guess a valid stance with REBOL could also be "You don't need to build
large applications. You can build small, manageable, apps and avoid 90% of
the overhead a large system requires (as exemplified by the IOS model). Has
anyone built any large systems with REBOL that can speak about the pros and
cons?
OK, on to the object-related questions.
Overhead:
Objects in REBOL get a copy of the entire spec block for that object,
correct? So, if I have 100,000 pixels to deal with, I probably don't want to
create an rgb-color object for each of them. I would either just deal with
them as tuples or, perhaps, write functions to access each part of the tuple
with a human-friendly name rather than the index in the tuple. E.g.
rgb: context [
red?: func [value[tuple!]][value/1]
green?: func [value[tuple!]][value/2]
blue?: func [value[tuple!]][value/3]
red: func [value[tuple!] new-value[integer!]][
value/1: new-value
return value
]
green: func [value[tuple!] new-value[integer!]][
value/2: new-value
return value
]
blue: func [value[tuple!] new-value[integer!]][
value/3: new-value
return value
]
]
If this line of thinking is completely whacked, let me know.
Private Data:
There doesn't seem to be any way to create private members in objects. Am I
missing something or is this not considered an issue? If there are members
that an object relies on, in order to be in a valid state for example, you
don't want people messing with them and breaking the object. I'm guessing
the solution to this is to use protect and unprotect. Has anyone done
anything like this? Am I being too paranoid? :)
Does anyone bother to use accessor functions for data members or is the
general practice, as it appears, to just declare members as public?
Naming Conventions:
Many languages use the set/get prefix on accessor method names. For example:
rgb-color: context [
_val: 0.0.0
get-red: does [_val/1]
get-green: does [_val/2]
get-blue: does [_val/3]
get-value: does [_val]
set-red: func [new-value[integer!]][_val/1: new-value]
set-green: func [new-value[integer!]][_val/2: new-value]
set-blue: func [new-value[integer!]][_val/3: new-value]
set-value: func [new-value[tuple!]] [_val: new-value]
]
I think REBOL gives us a better option, but I'd like to hear what others
think about the following:
rgb-color: context [
_val: 0.0.0
red?: does [_val/1]
green?: does [_val/2]
blue?: does [_val/3]
value?: does [_val]
red: func [new-value[integer!]][_val/1: new-value]
green: func [new-value[integer!]][_val/2: new-value]
blue: func [new-value[integer!]][_val/3: new-value]
value: func [new-value[tuple!]] [_val: new-value]
]
In the above code _val is considered a private data member, identified as
such by the leading underscore. Is this an acceptable convention or is there
another one in use that I should consider?
Thanks for any comments! ...and sorry for the lengthy message.
--Gregg
[2/4] from: chrismorency:videotron:ca at: 18-Sep-2001 21:15
Hi,
<part of solicitation snipped, see original message>
> If I asked "Should I use objects?", the answer would probably be
> "sometimes". There will be times when I don't need them and times
> when I do. I just need to figure out what my own rules are about
> when to use them. If anyone else has guidelines that they use,
> I'd love to hear what they are.
This is part of what I like with Rebol, you can do procedural, "objectual"
or contextual programming. I personnally prefer to do OOP because I work
with OOP daily, however this is your choice ! It all depends on your need
and how you prefer to accomplish the task. I see programming language like a
methodology, you can have a lot of ways to do something, some are good some
are bad, some are better than others but doesn't mean they're the fastest,
easiest... I think programming from a human point of view is not an exact
science.
Your question reminds me of a discussion I had with a friend earlier this
week about OOP. This is farfetched, but given all the time, all the
ressources (human and material) and comprehension (human) about a model,
let's say the universe, your could code it in OOP.
I see contexts as a way to communicate with a computer from a human and
social POV. Now, even though a model is developped in OOP for the computer,
the interaction is done through communication with context. Now this is
where I think Rebol excels. Now I can be wrong, During the week-end I read
some articles with Carl Sassenrath, and I read one from the late 90's where
he indicated his view on OOP, these can be interesting for people interested
in going pure-rebol.
> Overhead:
>
> Objects in REBOL get a copy of the entire spec block for that object,
> correct?
True, the way object! is implemented currently in Rebol, you may end with a
lot of overhead and memory consumption. I'm currently working on a personal
re-implementation of inheritance under Rebol including using Classes and
Objects, part of which is coded and other in my mind... I was sitting at my
computer to write a document on it actually so I don't loose any idea...
while writing this email ;-)
> Private Data:
> There doesn't seem to be any way to create private members in
> objects. <snip> I'm guessing the solution to this is to use
> protect and unprotect. Has anyone done anything like this?
> Am I being too paranoid? :)
Some OOP programming language enforce the idea of public and private (C++,
Java?, VB), however some don't (SmallTalk (VA atleast), Rebol..) I
understand the reasons why you would like to protect things, however the
later languages adopt another POV which basically say : let the programmer
know how to code, enforce it's methods and do the right thing, which offers
you some freedom...
> Does anyone bother to use accessor functions for data members or is the
> general practice, as it appears, to just declare members as public?
> Naming Conventions:
> Many languages use the set/get prefix on accessor method names.
I usually do, even under Rebol, I use the prv- prefix for private word, set-
prefix for setters, val- for validations and no prefix for getters : for
example :
person: make object! [
prv-name: ""
set-name: func [a-name] [self prv-name: a-name]
name: func [] [return (self prv-name)]
]
person/set-name "John Doe"
print person/name
I personnally like the way it look + it simplify a lot of coding for the
getter ;-)
Regarding self, notice the way the person object is implemented above, which
seems to be the standard way to refer to self in Rebol in the majority of
scripts...
I personnally prefer the following, which remains true to how object and
methods are accessed in rebol... also it permits the developer to remove a
lot of parenthesis when doing OOP and returning value for getters.
person: make object! [
prv-name: ""
set-name: func [a-name] [self/prv-name: a-name]
name: func [] [return self/prv-name]
]
(notice also that I have removed the type validation in the function, which
at first may seem stupid, but I prefer to consider everything as an object
like in some other language and manually validate my input through declared
validation function... now all my methods usually returns something, or true
of false to indicate success or not... (especially for setters).
> I think REBOL gives us a better option, but I'd like to hear what others
> think about the following:
<<quoted lines omitted: 9>>
> value: func [new-value[tuple!]] [_val: new-value]
> ]
Usually the methods or functions with ? at their end in standard rebol seems
to indicate a type-verification or validation of some-sort... and "does"
will translate to func with objects... I haven't tried with context though.
Here is how I would have done it... notice that the code is unfortunately
not as simple as yours, but however demonstrate local validation of type
without enforcing type in the func declaration, this is to illiminate error
;-) and use true or false for success... the set- red green blue methods
could have use a generic set- method that would have included a value to
indicate the tuple position etc ;)
rgb-color: make object! [
prv-rgb-color: 0.0.0
val-rgb-color?: func [a-rgb-color] [return tuple? a-rgb-color]
set-rgb-color: func [a-rgb-color] [
return either (self/val-rgb-color? a-rgb-color) [
self/prv-rgb-color: a-rgb-color
true
] [
false
]
]
rgb-color: func [] [return self/prv-rgb-color]
set-red: func [a-color] [
return either (self/val-color? a-color) [
self/prv-rgb-color/1: a-color
true
] [
false
]
]
set-green: func [a-color] [
return either (self/val-color? a-color) [
self/prv-rgb-color/2: a-color
true
] [
false
]
]
set-blue: func [a-color] [
return either (self/val-color? a-color) [
self/prv-rgb-color/3: a-color
true
] [
false
]
]
val-color?: func [a-color] [
return either (integer? a-color)
[
either ((a-color >= 0) and (a-color <= 255)) [
true
] [
false
]
] [
false
]
]
red: func [] [return self/prv-rgb-color/1]
green: func [] [return self/prv-rgb-color/2]
blue: func [] [return self/prv-rgb-color/3]
]
> In the above code _val is considered a private data member, identified as
> such by the leading underscore. Is this an acceptable convention
> or is there another one in use that I should consider?
I personnally prefer prv-... but _ seems to be becomming popular and I might
adopt it myself...
> Thanks for any comments! ...and sorry for the lengthy message.
Hope mine have been appreciated, however I maintain this how I do it, which
does not seem to be the current standard popular way objects are
implemented... or the best way to do it ;-)
Best,
Chris
[3/4] from: greggirwin:starband at: 18-Sep-2001 20:57
Thanks Chris!
Good thoughts all. You sparked a thought about one thing I really need to
get a handle on when I design functions: the return value. I'm very used to
a procedural approach but the more REBOL code I look at, the more I see that
returning an intelligent value that can be used in context by the caller to
minimize the code they need to write is incredibly valuable.
I'm sure as time goes on I'll get better at sifting for elegance.
Thanks again for your response!
--Gregg
[4/4] from: koopmans:itr:ing:nl at: 19-Sep-2001 9:11
Hi Greg,
I am working on a large project largely written in Rebol.
There is more than 3 man year in it and some 7000 lines of code, possibly
10-15 thousand when finished.
So yes, you can (and should) use Rebol (Command) for serious projects.
Though I think that when using Rugby, erebol, etc. as libraries your code
always will be smaller (these are part of our project).
Think of Rebol as Java code size divided by 5 (at least).
--Maarten
Notes
- Quoted lines have been omitted from some messages.
View the message alone to see the lines that have been omitted