BORING PREFACE:
Perhaps I should clarify my purpose. My 25+ year career in computing
(including 12 years teaching math and computing science) has routinely
involved learning new programming languages to tackle a project-du-jour.
My experience is that when I have trouble getting my head around some
feature of a new language, it is because I don't have a good conceptual
model for it (yet!) My attempts to discuss models of REBOL features
are motivated by (1) my desire to understand REBOL better myself, and
(2) my hope that some of these ideas may help others to understand it
better. I know that some people's learning and thinking style is
top-down and conceptual (I fit into this group), while other people
have a bottom-up and concrete style. That's perfectly OK -- neither is
"better" than the other, just different.
However, I've seen lots of discussion on this mailing list over issues
that, based on my experience, seem to be symptoms of model problems.
These include confusion over scoping, inheritance, reference aliasing,
persistence, closures, and relationships between data types. All of
these are well-known topics in computing science; discussing how
different languages handle them differently is mother's milk to a
computing science guy. However, some of us (myself included) seem to
be having trouble getting clear focus on how REBOL deals with some of
these areas. By attempting to suggest ADDITIONAL (not competing!)
models, or to clarify where I believe the existing documentation has
the potential for misunderstanding, I'm just trying to flatten the
learning curve for myself and others.
I have a great deal of respect for what Carl and the rest of the REBOL
team have accomplished to date, and appreciate the magnitude of the
task that lies in front of them (bringing up REBOL/core and /command
on the advertised platforms, getting the book out, etc.) My hat is
off to them and I wish them well. I just hope some of this discussion
helps the process along.
ACTUAL REPLY:
[EMAIL PROTECTED] wrote:
> ...
> I think the built-in help is usually pretty clear on this issue:
>
> >> ? next
> Returns the series at its next position.
> [...]
> >> ? insert
> Inserts a value into a series and returns the series after the insert.
> [...]
>
> There's nothing in the description of NEXT to make you think it
> modifies the series, and the description of INSERT makes it clear
> that the series will be modified... So I don't think it's quite
> fair to say that series operators are all lumped together.
>
Actually, your example illustrates exactly the point I was trying to
make. Both are described as doing something with "the series", but
sometimes "the series" refers to a particular VIEW of the data, while
other times "the series" refers to the underlying data itself. The
phrase "at its next position" implies that position is an attribute of
the series itself. That understanding would lead to the conclusion
that
a: "123456"
b: next a
leave 'a and 'b referring to distinct series values, as 'next or
'length? yield different values when applied to 'a and 'b. So I'm
suggesting that making clear the distinction between a view and the
underlying data would help clarify what is really happening (at least
to slow learners like me). In the same vein, I was recently surprised
by
>> a: "123456"
== "123456"
>> b: next a
== "23456"
>> append b "-YOW!"
== "123456-YOW!"
>> b
== "23456-YOW!"
in which "the series" returned by 'append is clearly different from
"the series" referred to by 'b.
>
> To tell you the truth, I found your model too abstract to be easily
> understood (but then I've never studied the theory of computer
> languages). Except for contexts and binding, REBOL is a language
> that's easily understood at a very concrete level.
>
> Perhaps what you were saying could be described this way:
>
> Series values have two aspects: a sequence of data, and an index to
> a position within that sequence. Any number of indexes may refer to
> a single series. When you construct a series, you will get an index
> to the first element in the series. An index defines a position
> within a series from which you may read data (as with COPY or PICK),
> or at which you may make a modification to the series itself (as
> with INSERT or POKE). You can also use an index as a point of
> reference for defining a new index (as with NEXT, AT or SKIP).
>
I found that description to be inconsistent. It mixes the use of the
terms "sequence" and "series" in a way that perpetuates the confusion
I'm trying to eliminate. After rewording it to address that issue
of terminology:
Series values have two aspects: a sequence of data, and an
index to a position within that sequence. Any number of
indexes may refer to a single sequence. When you construct
--------
a value that can support a series, the default index refers
------------------------ --------------------
to the first element in the sequence. An index defines a
--------
position within a sequence from which you may read data
--------
(as with COPY or PICK), or at which you may make a
modification to the sequence (as with INSERT or POKE).
--------
You can also use an index as a point of reference for
defining a new index (as with NEXT, AT or SKIP).
the resulting version appears to be exactly as abstract/concrete
as the concept I suggested earlier. The only substantive difference
that I can find is that I said "series" where you said "index"; both
versions separate the underlying data from a reference to a
specific position within that data, which I believe to be the key
point of confusion.
>
> As for "superclasses" like ANY-STRING! (called pseudotypes in REBOL),
>
I intended the quotes around "superclasses" to indicate that I knew
that wasn't the standard REBOL terminology, but that the concept was
one that someone familiar with OO would understand (and be looking
for in a language that is described as a "relative expression-based
object language"). I apologize if I didn't make that clear.
The problem is that there's nowhere (that I've found) that defines
what a pseudotype really is! Based on the examples given in
http://www.rebol.com/manual/valabout.html
it appears that a pseudotype is just shorthand for referring to a
set of types, so that
any-block? foo
is shorthand for
any [block? foo list? foo hash? foo paren? foo]
and
bletch: func [gorp [any-block!] ...
is shorthand for
bletch: func [gorp [block! list! hash! paren!] ...
which is a handy piece of syntactical sugar. However, it's not clear
from the examples whether that's all there is to a pseudotype, and
there's nowhere I have found that answers that question.
I'm leaning toward that view, because experimenting with pseudotypes
produces another surprise, as follows:
>> help make
Constructs and returns a new value.
Arguments:
type -- The datatype or example value. (any-type)
spec -- The attributes of the new value. (any-type)
>> any-type? any-string!
== true
>> any-string? "123456"
== true
>> make string! "123456"
== "123456"
>> make any-string! "123456"
** Script Error: Cannot use make on datatype! value.
** Where: make any-string! "123456"
Although 'make is documented as taking a first argument satisfying
'any-type?, and 'any-string! satisfies 'any-type?, 'make barfs
when asked to construct an 'any-string!, so clearly 'any-string?
is not a first-class type.
My point is simply that examples are good (and necessary!) when
I'm just getting my foot in the door. However, really understanding
a language requires that I have access to a complete specification.
The risk of trying to infer a specification from examples and
experience is exactly the same as the risk of trying to infer the
correctness of a program from test runs -- there's no way to
guarantee that the tests/examples have actually been sufficiently
comprehensive.
I'm perfectly willing to contribute some effort to help create the
explanations that will help boneheads like me -- however, I've gotta
understand it myself first!
-jn-