[REBOL] Re: using type? with switch
From: joel:neely:fedex at: 1-Oct-2001 18:12
Hi, Gregg,
Gregg Irwin wrote:
> Is is possible to use the result of type? with switch? I.e. if
> I want to use switch to dispatch based on different data types,
> it seems I have to use to-string on the result of type? for use
> with switch. Is that the case or am I missing something?
>
Consider the fragment below:
>> selblk: [
[ integer! [print "int"]
[ string! [print "str"]
[ block! [print "blk"]
[ ]
== [
integer! [print "int"]
string! [print "str"]
block! [print "blk"]
]
>> foreach item selblk [print type? :item]
word
block
word
block
word
block
This shows that the "case" elements of the block are WORD!
values, not DATATYPE! values (because they haven't been
evaluated yet). OTOH, we can do this:
>> foreach item reduce selblk [print type? :item]
datatype
block
datatype
block
datatype
block
to get a collection of DATATYPE!/BLOCK! pairs. This means
we'd expect to reduce the type/action block to get the
desired behavior. For example
>> vi: 12
== 12
>> switch/default type? vi selblk [print "unknown"]
unknown
>> switch/default type? vi reduce selblk [print "unknown"]
int
and
>> vs: "Hello, world!"
== "Hello, world!"
>> switch/default type? vs selblk [print "unknown"]
unknown
>> switch/default type? vs reduce selblk [print "unknown"]
str
because the datatypes resulting from TYPE? Vx don't match
the words in the non-REDUCEd version, but do match the
datatypes in the REDUCEd version.
Unfortunately, there's still a gotcha!
>> vb: [1 2 3]
== [1 2 3]
>> switch/default type? vb selblk [print "unknown"]
== string!
>> switch/default type? vb reduce selblk [print "unknown"]
== string!
Which looks totally mysterious, until we take into account
that SELECT apparently has a different behavior if the target
is a datatype: it matches the first value of that datatype,
rather than matching the datatype value itself!
>> foo: [1 "HI" #"X" 1.2 http://www.rebol.com [x--y--com] "EEK"]
== [1 "HI" #"X" 1.2 http://www.rebol.com [x--y--com] "EEK"]
>> select foo integer!
== "HI"
>> select foo decimal!
== http://www.rebol.com
>> select foo url!
== [x--y--com]
(And, remember, SWITCH is built on top of SELECT, as you can
see by entering SOURCE SWITCH in the console.)
This means that TYPE? VB evaluates to BLOCK! which matches
the first "action block" in the target/action pairs (item 2)
which returns the next element (item 3) as the result to be
DOne by the SWITCH.
You can use a couple of alternative work-arounds to this
very non-intuitive (and undocumented?) state of affairs:
1) make the selection target a string, as you mentioned
(it would be nice if TO-WORD could take a datatype as
an argument which would then match in the non-REDUCEd block,
instead of blowing up in one's face!)
2) create your own SWITCH variation that avoids the problem
by forcing target/action parity:
>> case: func [[throw] val cases [block!] /default def] [
[ either val: select/skip cases val 2 [do first val] [
[ either default [do def] [none]]
[ ]
>> case/default type? vi reduce selblk [print "unknown"]
int
>> case/default type? vs reduce selblk [print "unknown"]
str
>> case/default type? vb reduce selblk [print "unknown"]
blk
HTH!
-jn-
--
This sentence contradicts itself -- no actually it doesn't.
-- Doug Hofstadter
joel<dot>neely<at>fedex<dot>com