Should DATATYPE! be killed off (in favor of @integer, @word, etc?)

Datatypes have a couple of problems. One is that there's no clear representation for them literally:

rebol2>> word? first [integer!]
== true

rebol2>> type? 10
== integer!

rebol2>> word? type? 10
== false

So we're on the cusp of having to use some notation for datatypes like #[datatype! "integer!"] -or- perhaps see them as being expressed through an existing type. We also face the question of extensibility of types...and it's hard to think of a better extensibility mechanism to use than the existing symbol engine that is behind ANY-WORD!.

Yet making them WORD! is not very desirable. We are used to writing things like make object! [...]. And we don't want MAKE to have to quote its argument. Hence, OBJECT! would have to evaluate to something.

We could say object!: 'object! but that seems like it would get into some ugly situations.

What about the new @WORDs?

What if @object! (or @object) could act as a datatype, as well as an ANY-WORD!?

It has the advantage of being inert in the evaluator:

if @integer = type of 1 [print "Sanity prevails..."]

You wouldn't have to worry about quoting it if you were using the actual type's symbolic name, vs. an alias:

switch type of first ['''1] [
    lit '''@integer [
        print "You can do this..."
    ]
    ...
 ]

Redbol compatibility could still work:

integer!: @integer

Though you'd need to do a little extra to work with quoting such names. But Ren-C is designed for it:

switch type of first ['''1] compose [
    lit '''(integer!) [
        print "You can do this..."
    ]
    ...
 ]

So the main question would be, how often is it that you have a slot that might want an @word -or- a datatype? How frequent is that need for polymorphism?

When I look at the landscape of problems, it seems to me that an evaluator-inert type that has an intrinsic extensibility like this would be pretty much ideal for denoting a datatype. No construction syntax, just good ol' reliable behavior.

Anyone have any particularly good arguments against the idea?

Thus Parse usage would be:

parse [1 2 3][some @integer]

Would that preclude any other potential usage for symbols in Parse?

Great minds think alike.

Yes, and PARSE is probably not the only example of a dialect where having a distinct otherwise-unused notion of DATATYPE! could come in handy, where the slot could be either symbol or datatype.

Would that mean:

parse [1 @integer 3] [some @integer]

would be successful?

(UPDATE: I think @integer! is probably wiser, to line up with the datatype name...since they are both ANY-WORD!s in this system, it makes sense to make them easy to compare. This possibly would give us a long-desired feature for datatype and word-of-datatype comparison equivalence)

In the context of the discussion, no.

@integer!, being interpreted as a datatype for purposes of the dialect, would be a parse instruction for integer matching.

However:

parse [1 @integer! 3] [@integer! '@integer! @integer!]

Would reach the end of the series (truthy).

We would presume that integer! would be a WORD! that evaluated to @integer! . So you could still say:

parse [1 @integer! 3] [integer! '@integer! integer!]

It would work by the same general theory that any WORD! which is used in a PARSE rule that's not a keyword is fetched to be the associated rule.

Should DATATYPE! be killed off (in favor of @integer, @word, etc?)

Something to think about with this question is regarding a more OBJECT!-like notion of what a datatype is, where that object might have various descriptive properties (like the numeric limits of a type, or precision, or other characteristics).

If "types" are ANY-CONTEXT!, then they can do this. But if they are simple @word!-s, then you'd have to go through a lookup (at minimum) to get an object that matches the descriptor.

This may point us to a notion of a difference between the kind of a value, and the type of a value. The kind would be something more mechanical regarding the cell structure (like to say that something is an OBJECT!). Whereas the "type" could be richer.

>> book!: make object! [author: title: _]

>> item1: make book! [author: "Aldous Huxley" title: "Brave New World"]

>> item2: make book! [author: "George Orwell" title: "1984"]

>> kind of item1
== @object!

>> object! = kind of item1
== #[true]

>> type of item1
== make object! [author: _ title: _]

>> (type of item1) = (type of item2)
== #[true]

Hence it may be that these wordlike things are only suitable for the kinds. But this is very speculative. We're talking about features and concepts that were never designed (!), yet people would probably like to see fleshed out somehow.

While demoing some of the quoting in the conference, it was clear that dealing with that is going to be a bit of a puzzle for some minds--and so we should do everything we can to make it more obvious.

But... using quoted types to reflect quoting on values has some counter-intuitive properties in evaluative contexts, e.g. with the now evaluative SWITCH...

 switch (type of first ['''foo]) [
     ''''@word [
         print "...needing four quotes here strikes me as non-obvious."
     ]
     lit '''@word [
          print "...and needing LIT undermines datatype as inert @WORD!"
     ]
 ]

This led me to a concept I outlined in chat that we make use of the somewhat superfluous-seeming member of the new inert @ family, the @[...] blocks...

 >> type of first ['''foo]
 == @['''word]

If we use this particular part in the box as a datatype! replacement, we get the opportunity for richer structure. @[matrix 20x20]. And if we let the quoting level be carried on the first element of the type, we also get a fair amount of leverage from that.

Of course we can still keep our shorthands, perhaps adding more:

 integer!: @[integer]
 integerQ!: @['integer]

And it frees up @(...), @word, @some/path for other applications in dialects, because only the @[relatively unloved "new-lit-block"] would be taken (and only in cases where that dialect had reason to be dealing in datatypes).

Seems like an exciting idea to me!

1 Like

I'm still liking this direction. There are a few implications to notice.

One is that TYPE OF is coming back with something more granular than just QUOTED! for things that have quote levels. This preserves the historical (and desirable) behavior. Consider that we likely want:

rebol2> (type? first ['x]) = (type? first [x])
== false

rebol2> (type? first ['x]) = (type? first ['x/y])
== false

If the type of 'x were simply @quoted, then though the former would be false, the second would be true. This suggests a different operation that would say that 'x and 'x/y were both instances of QUOTED!.

But TYPE OF returning an ANY-ARRAY! has the properties we're looking for. It's a distinct type from BLOCK! that is nonetheless irreducible, we can do comparison, and symbolic manipulation via QUOTED and UNQUOTED.

 >> unquoted @['integer]
 == @[integer]

 >> (quoted integer!) = type of first ['10]
 == #[true]

Yet the fact that sometimes we might want to know something is QUOTED! and not care about the specifics raises a bigger point: that there are various depths of patterns to match in "types".

This already existed before arbitrary quoting: e.g. ["a" 10] and [<b> 20 #foo] are both BLOCK!s, but if you were expecting a two element block with a TEXT! and an INTEGER! then they are effectively not matching types. It's the precedent of LIT-WORD! and LIT-PATH! that forced having to have a solution for quoting. But people have wanted something for this as well.

As time has gone on, the applications of @word @pa/th @[bl o ck] and @(gr o up) have become wider. The "useless" @[bl o ck] datatype is no longer useless, and has many non-datatype applications.

I just mentioned in a post that its "as-is" meaning is likely being picked up in PARSE to mean "literal content, not a parse match rule". So keep @[some integer!] won't keep some number of integers...but the actual words "some integer!".

Note: I see even this would be an overloaded meaning if the append [a b c] @[d e] change for meaning append [a b c [d e]] went through (it hasn't yet, so APPEND/ONLY status quo is still how you add things as-is). Which only goes to show the point that @-blocks are popular customers these days...

This isn't to say we can't still use @[...] for datatypes. But it does push on the "substitutability principle". If you have:

integer!: @[integer]

Then someone will write a parse rule like keep integer! and have an expectation of what that means. And they can be justifiably surprised when keep @[integer] acts completely differently.

It's important to remember that a "universal substitution principle" already doesn't exist:

print "Hello"
; -- vs. --
word: first [print copy]
word "Hello"

Though maybe it's more acceptable when you know the thing you're working with is evaluative, so you don't expect it to work the same way.

Maybe that suggests that datatypes should reuse a type that would be evaluative if you don't quote it or fetch it from a word? :thinking:

>> type of 10
== :(integer)

That's a pretty weird idea. But if you typed in :(1 + 2) and got 3, you would be suspicious of just dropping something that said :(integer) somewhere and expecting it to act like a datatype. And maybe that's a good expectation to be calibrated to.

Issue is that we have to remember that a key to this datatype is that dialect-wise, we have to be willing to sacrifice it for the meaning of "match this datatype". That's easiest to do if it has its own notation...but the whole question of this thread is whether that's avoidable, especially given the need to encode quotedness into the type.

Of course it's still a deep thought...which is why we're still using #[datatype]...but the thoughts continue.

1 Like

To have clean, non overloaded way to describe datatypes, they would need a dedicated symbol for datatypes.
Actually I've never used "!" in words myself, so I wouldn't have a problem with enforcing that only types can have "!" in their name.
Just mentioning it.

Clearly; but what I'm trying to get at is that when you consider something like PARSE, you already have the case that a BLOCK! which isn't quoted is a rule. So to match a block literally you have to quote it.

  ; This won't work how you want
  block: [some "a"]
  parse [[some "a"] [some "a"]] [2 block]

  ; The theory is that this will work, but it's slightly counter-intuitive
  block: quote [some "a"]
  parse [[some "a"] [some "a"]] [2 block]

  ; We can imagine there being an escapable LIT rule
  block: [some "a"]
  parse [[some "a"] [some "a"]] [2 lit :(block)]

  ; But fetch/match literally might be a use for for @...
  block: [some "a"]
  parse [[some "a"] [some "a"]] [2 @block]

The point is that we are already on the hook for datatypes serving multiple purposes. LOGIC! is continue the parse or not, INTEGER! is a repeat count.

So to my mind, the concept of @[...] being a datatype isn't so bad. If we were to pursue my idea above of using @ to get literal matches against a variable or expression's result, you've got @word @pa/th @(co de) ... but if you want to match a literal block there's '[...]. So it frees up @[...]

The issue with coming up with yet another lexical construct is that I think types need to be structural, e.g. to encode quote levels (and more). With other data types wearing a lot of hats, I don't feel particularly bad about the idea of using @[...]. But whatever is done, needs to be done in a considered fashion.

I've only thought of using exclamation points for breakpoints or some kind of error, !!. But the thing is that if we took away ! from word-space and gave it to datatypes, then it would make it hard to alias datatypes through the evaluator.


A random recurring thought I've had is that datatypes are URLs, but that something like the @ types cue "type matching" to follow them through some level of dereference:

Hazy thought:

  type-context: make object! [
       integer: http://example.com/t/core/integer
       ...
  ]

  integer!: bind @[integer] type-context

  >> print mold integer!
  == @[integer]

  >> type of 3
  == type://example.com/core/integer

  >> integer! ~ (type of 3)
  == type://example.com/core/integer  ; the truthy fuller resolved item

  >> block! ~ (type of 3)
  ; null

Similar to what I've suggested about a smooth slope from refinement to PATH! to URL!...

  >> error/id
  == error://example.com/lysol/bad-medicine

  >> /bad-medicine ~ error/id
  == error://example.com/lysol/bad-medicine  ; the truthy fuller resolved item

  >> /beer/bad-medicine ~ error/id
  ; null

It's not a very realistic goal to do quality system future-proofing with ASCII. :-/ But maybe there is a sweet spot somewhere in here.

1 Like

So with the applications in PARSE as well as in DO of these types, I think we can essentially consider their use in datatypes to be off the table.

Hence it's time to shift thoughts over to the likes of #[integer] or $[integer] or whatever else, but remembering that we still have to have representations for some kind of map/object literal.

Anyway, as much of a bummer as it is to sort of be back to the drawing board on datatypes...the @xxx are doing very nicely, I think.

2 Likes