Note: This message contains a lot of tedious observations on how MAKE works,
but there are some items of more general interest following.
Hi Elan,
Sorry I've had to delay responding. You wrote:
>That's the problem. type? any-string! indeed returns datatype! However,
>any-string! is not a datatype!. As you point out later, it's a
>pseudo-type!. Therefore, it's a mistake when type? returns datatype! as
>any-string's type. Type? should report that any-string! is a pseudotype!,
>right?
>
>>
>>I <<think>> what happens here is that any-type! is not a fundamental
>>datatype,
>
>never heard of a fundamental datatype. According to make's help text it
>doesn't require a FUNDAMENTAL datatype, but a datatype. Perhaps make's
>attempt to use any-string! as a datatype! fails, and therefore ...
>eventually, REBOL reports the error.
I got the term fundamental datatype from the REBOL help file valabout.html:
Fundamental Datatypes
Following are the fundamental datatypes of REBOL. These are the scalar,
and constructed values. These datatypes are divided into scalars and
series.
The next section in this file begins:
Datatype Classifications
In addition to the types listed above, some REBOL datatypes are
pseudotypes. Pseudotypes identify a subset of datatypes. For example,
the number! pseudotype identifies the integer! and decimal! datatypes:
I think it's clear here that pseudotypes are treated as a kind of datatype.
Unfortunately there seems to be no provision as yet in REBOL's built-in
metalanguage for pseudotype.
Also, MAKE, in its interface, does not require any particular datatype; both
arguments are specified as any-type!, which means that any errors will occur
internally, during whatever processing MAKE performs.
>> ? 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)
Here's an example of (what I'd call) an interface function error:
>> length? 3
** Script Error: length? expected series argument of type: series port tuple.
** Where: length? 3
Note the word "expected" - this error happens, I take it, before LENGTH? ever
gets called.
Here's the error message from MAKE:
>> make any-string! "any-strings, anyone?"
** Script Error: Cannot use make on datatype! value.
** Where: make any-string! "any-strings, anyone?"
This seems to be an error message peculiar to MAKE, and I interpret it to
mean that MAKE "attempted" to make a new datatype, and failed. As I pointed
out before, MAKE will accept a TYPE argument of any type. I speculated in my
previous message that if the TYPE argument is a fundamental datatype! (as
explained in the REBOL documentation) it will attempt to make a data instance
of that type. If that argument is not a fundamental datatype!, it will
attempt to make a data instance of the same type. Here are some more amusing
examples:
>> make false true
== true
>> make false 0
== false
>> make false 1
== true
I have to revise my speculation. It appears that MAKE has a list of datatype!s
that it will use as datatype!s, and if the TYPE argument is not in that list,
it will attempt to use the TYPE argument as an example value. Notice:
>> make op! ">>"
** Script Error: Cannot use make on datatype! value.
** Where: make op! ">>"
Here op! wasn't in MAKE's list of make-able types (although it is a
fundamental datatype!), so it tried to use op! as an example value, and op!
is, of course, a datatype!.
>> make :+ ">>"
** Script Error: Cannot use make on op! value.
** Where: make :+ ">>"
Here MAKE attempted to use the + operator as an example value, and since its
datatype, op!, is non-make-able, an error occurs.
There are a couple of other reasons for regarding pseudotypes as datatype!s.
Pseudotypes work just the same with as other datatype!s in function
specifications, and they also work the same with FIND:
>> find [21 "string" 22] string!
== ["string" 22]
>> find [21 "string" 22] any-string!
== ["string" 22]
>> find [21 "string" 22] series!
== ["string" 22]
Hope this clears up a little of the datatype!s mystery.
Conclusion: pseudotypes are datatype!s, they just aren't make-able.
***** SPECIAL BONUS FOR DATATYPE ENTHUSIASTS *****
The datatype hierarchy in the documentation is a bit off. Here is my
corrected version.
any-type
any-function
action
function
native
op
any-word
get-word
lit-word
refinement
set-word
word
bitset
char
date
error
logic
money
none
number
integer
decimal
object
port
series
any-block
block
list
lit-path
hash
paren
path
set-path
any-string
binary
email
file
issue
string
tag
url
symbol
time
tuple
unset
If you don't believe some of this, you can check:
>> any-block? first [this/is/a/set-path:]
== true
I couldn't believe this at first, but since all the path values can be made
from blocks, it does make sense.
Here is a function I sent to the list before to print out all the types a
piece of data belongs to:
show-all-types: func [
{print out all relevant datatypes for a value}
value [any-type!]
/local typelist valuelist to-do
][
foreach [type list] reduce [
unset! "unset!"
datatype! "datatype!"
action! "any-function! action!"
op! "any-function! op!"
][
if type = type? get/any 'value [print ["any-type!" list] exit]
]
alltypes: []
if tail? alltypes [
foreach word first system/words [
if datatype? get/any word: in system/words word [
append alltypes get word
]
]
]
typelist: copy []
valuelist: head insert/only copy [] :value
foreach type alltypes [
if find valuelist type [
append typelist mold type
]
]
print typelist
]
***** EXPLANATION OF REBOL PROGRAMMING TRICK *****
Here's a use for the confusing self-modifying REBOL code feature.
SHOW-ALL-TYPES makes a list of datatype!s by iterating through all of the
words. We don't want to do this everytime, so we initialize ALLTYPES this way:
alltypes: []
The second time this function is run, ALLTYPES is initialized to a complete
list of all the datatype!s. Unfortunately, four of these types won't work
properly with FIND, so I had to provide special processing for them.
See ya,
Eric