Hi Joel,
You are certainly correct in pointing out that pointers and indexes can be
converted into each other. But you do have to be careful:
I am sure you agree with me that if i is an index into a buffer,
int i; char buf[10], *p;
then trying to access the element at buf[i] is quite something different
from using the index as a pointer, *i. That would be a huge bug.
Once I have modified the value of a pointer
for (p = buf; *p; p++) { printf ( "%c", *p ) }
I should not expect that *(p+i) is the same thing as buf[i]. The two
notations are convertible, provided I am aware of their differences.
And both Kernighan AND Ritchie would be surprised if given
char buf [10], *p;
I were to say:
for (buf = p; *buf; buf++) { printf ( "5c", *buf ) }
in place of the 'for expression I used above.
So, yes, I concede that they are convertible, without a question, but it's
certainly a good idea to keep in mind, what a pointer is, what a buffer is,
what an index is and in what ways they differ. If you're to survive as a C
programmer that is.
In a different way it is also true for REBOL that I can peek, poke and
eavesdrop in many ways:
first at series 10
pick series 10
and I can always say that I am refering to the 10th element of the series,
no matter how I access it, when I discuss the expressions above. Yet I can
construct values as references to a series, only if those values have the
datatype word! I would like to refine this statement.
It's an interesting thing with series. (Probably you discuss it in your
series essay, which, I admit, I still haven't read, but I think for a good
reason. I can only take very little time right now for the list, and I am
quite sure that once I start reading your essay, I will want to spent a
long time thinking about it and perhaps even some time responding to it
intelligently.)
I can construct a reference to a series, the word block:
>> block: [1 2 3 4 5]
== [1 2 3 4 5]
and embed the word block in a containing block:
>> container: [block]
== [block]
I can also do that programmatically:
>> insert container: [] 'block
== []
>> container
== [block]
REBOL visually represents the embedded reference as the word block. Even
more, type? also recognizes the embedded reference as a word:
>> type? first container
== word!
And - as we all know - I can retrieve the value being referenced - using get:
>> get first container
== [1 2 3 4 5]
None of this is sensational.
I can also say:
>> c: head insert/only [] block
== [[1 2 3 4 5]]
Since the word is evaluated before 'insert receives its argument, what is
inserted in c is visually represented as the value and not as the word by
which I was referencing it (also quite known and not sensational). Insert
has no clue that I was referencing the block I inserted using the word
'block, which is fine:
>> c
== [[1 2 3 4 5]]
It's perhaps a little more interesting to note that type? also identifies
the inserted block as a block, and not as a reference to a block:
>> type? first c
== block!
But we know that the inserted block is inserted only as a reference:
>> insert first c 1000
== [1 2 3 4 5]
>> c
== [[1000 1 2 3 4 5]]
>> block
== [1000 1 2 3 4 5]
Inserting 1000 into the head of the block embedded in c results in a
modification to the block referenced by the word 'block. Not much of a
surprise. But I think terminologically we need to be able to distinguish
between an embedded reference of the type
container: [block]
and a reference of the type
>> c
== [[1000 1 2 3 4 5]]
They act the same way with in some respects and different in others. I
already demonstrated the use of type?, which in one case returns the
datatype of the referer, whereas in the second case type? returns the
datatype of the value being refered to. Another example:
Even though in both cases the value is being referenced, we can access the
first item of the embedded block using first first
>> first first c
== 1000
whereas - even though in the second example the word 'block is also a
reference to the exact same block - first first container will return an
error:
>> first first container
** Script Error: first expected series argument of type: series money date
object port time tuple
any-function.
** Where: first first container
In short, if we wish to access the value being referenced in the 'container
example:
>> container: [block]
== [block]
we have to explicitly dereference the word:
>> insert get first container 9999
== [1000 1 2 3 4 5]
Since I must *explicitly* dereference the embedded word 'block in order to
get at its value, whereas REBOL *automatically* dereferences the embedded
literal block for me, when I try to insert something into it, or when I
retrieve its datatype using type?, I think it would make sense to refer to
values of type word! as explicit references, whereas we could refer to
embedded series as automatic references.
If you follow me in the distinction I am making here, then I would refine
my previous statement, saying that:
The only values that can act as explicit references are values of the type
word. Besides being referenced explicitly by words, series values can also
be referenced by automatic references embedded in other series. In the same
way that words defined in a local context can be considered to be embedded
in the local context's block, series defined in the global context can be
considered to be automatic references in the global context.
Then we can say that automatic references in the GLOBAL context are
disposed of by the garbage collector. In the global context only explicit
references protect a value against being recycled. In contrast, in local
blocks automatic references are protected by the local context from being
recycled, as long as the local context as a whole is not garbage collected.
Finally we can say that the context of a value can be extended, when it is
explicitly or automatically referenced from within a surviving context.
Take Care,
;- Elan >> [: - )]