Could Each Datatype Have a "Second" (Hidden) "Slot"

From some time I am having the idea that each datatype could have a second value slot where you can set a context where I can store replacement handling methods for set/get and also other functions and any data you have, so you can patch the standard Rebol handlings and have also additional data/functions.

But as it happens, Ren-C objects and functions actually do have this "second slot".

It's where modules store their headers, and where functions store their help (for instance).

>> info: meta-of :append  ; old name for second slot is "META-OF", needs renaming

>> info.parameter-notes
== make frame! [
    return: '
    series: "Any position (modified)"
    value: {What to append (NULL produces TRY-interceptible failure if no-op)}
    part: "Limits to a given length or position"
    dup: "Duplicates the insert a specified number of times"
    line: {Data should be its own line (use as formatting cue if ANY-ARRAY!)}
]

There's more leeway in finding space for this slot in things like objects and functions, because they don't try to fit all of their data into a "cell". Things like DATE! are too packed in the current implementation--they use all the cell's space. But of course there could be a way to open this up, and the dates could split their contents out into a separate allocation...question is if it's worth doing so.

I wouldn't say it's the worst idea that INTEGER! be able to have additional properties, but it's not clearly an important idea to pursue at the moment. However, being able to give functions data fields is something that is done in practice in things like JavaScript...and has shown value there. So we have it, and it would be nice if the feature were exposed better.

I have not understood if you are talking at datatype level or value level. My idea is to store an object with methods to manage the current value. It would be nice if you could optionally instruct ren-c to use these methods and override the standard set/get/clear... of other inner Rebol metal language. So, it would be like having a custom u-type for each value.

This doesn't quite address specifically what you're looking for, but it is somewhat pertinent and it's on my mind so I'll put it here for now.

Having spent a bit of time swimming in the Javascript waters lately, I see some value in a middle ground between Javascript objects and Rebol ports (perhaps this an evolution in thinking since my CLASS proposal).

Ports kind of are the closest thing to a custom Rebol datatype (I'm not the first to suggest this) with some ties to the URL type for something close to top-level representation in the language. Javascript objects go a bit deeper into prototypical inheritance than Rebol objects and have chameleon-like qualities in the way Rebol ports do. Consider how you can, for example, manipulate the way an arbitrary object interacts with standard operators:

function mySpecialNumberType(value, unit) {
    this.value = value
    this.unit = unit
}

Object.assign(
    mySpecialNumberType.prototype, {
        valueOf: function () {
            return this.value * 2
        },

        toString: function () {
            return '' + this.value + this.unit
        }
    }
)

let num = new mySpecialNumberType(
    1, 'em'
)

console.log(
    [num + 2, num]
    .join(' ')
)

// => 4 1em

(with comments)

It runs a bit deeper than that and makes Javascript versatile in certain ways—as I said, I think there's some value in that.

A nice quality of Javascript objects is that the object prototypes are named, so it's generally easy to tell if an object conforms to the type you're expecting:

num instanceof mySpecialNumberType

There's no real way to hack 'primitive' objects in Javascript, so you can't change the way, say, a literal 1 or 'foo' is added or formed.

I should add, I do find the way Javascript's objects work in this way a little wacky (by specifying them first by their constructor and then their attributes and obscures their general usefulness :man_shrugging:)

If you put aside native IO, PORT! values in Rebol 3 are little more than a variant of OBJECT! and while you can't quite hack the language as in Javascript, you can still manipulate the way various ports react to the standard Rebol verbs, which kind of hints at the general area I'm interested in.

3 Likes

This is the sort-of equivalent in Rebol 3 (using R3-Alpha). Similarly wacky in the implementation for what it does, but you put the two examples together and there is a semblance of an idea there:

my-literal-value: my-special-num-type:1em

digit: charset "0123456789"
letter: charset "abcdefghijklmnopqrstuvwxyz"

sys/make-scheme [
    name: 'my-special-num-type
    title: "My Special Number Type"

    state: make object! [
        value: none
        unit: none
    ]

    init: func [
        this
    ][
        this/state: make state [
            parse this/spec/ref [
                "my-special-num-type:"
                copy value some digit
                copy unit some letter
            ]
        ]
    ]

    actor: [
        select: func [this property] [
            get in this/state property
        ]

        copy: func [this] [
            to url! rejoin [
                "my-special-num-type:"
                this/state/value this/state/unit
            ]
        ]
    ]
]

num: make port! my-literal-value

print [
    select num 'value select num 'unit
    copy num
]

; => 1 em my-special-num-type:1em

(with comments)

2 Likes

Sort of both...because how much space a value cell (instance of a datatype) has to spare for things like a second "slot" depends. A value like 19-Jul-2022/22:39:58.725-4:00 already uses up all the cell space (cell header, the date, the time, and the nanoseconds).

But that's just one detail. If you have a date value like that today, it is considered "immediate!". So if you pass a date to someone, they cannot change it and affect dates that you are holding onto.

If dates have more properties as you suggest, then this starts to get fuzzy. If I pass you a date, and you change some of these "second slot" properties, does it change the second slot properties on my date?

There's really no design behind user-defined types, so saying something is "like it" can't explain its behavior. It's defining an unknown in terms of an unknown...!

My push is for people to really talk in terms of concrete scenarios. What is the thing you are trying to accomplish, and how does the language feature provide something useful for that purpose.

So for instance: we certainly can provide some extra fields of user information that travels along with a DATE!. But there has to be some really killer advantage to doing so vs. making an object that has a date as a field. And that advantage has to be shown not to break down under slight scrutiny beyond a single example that makes it look a little nicer for one case...

We've got a lot of things to ponder, and @rgchris is offering some leads on that.

1 Like

Just a musing. For a long time I wished for strings with context. It came from doing tokenisation of mostly string data, wanting to keep the sequence of tokens in a block so that they could be simply re-joined together again after having extracted or manipulated some parts of the sequence based on type. By manipulation I mean simple series like operations such as replace or using parse.

Rebol has been really useful over other languages I've used for just reading in foreign syntaxes, overlaying it with just enough structure to complete a task and writing it back out. A smart search and replace based on simple structure.

I'd envisaged parse annotating substrings of the original with context to allow small ad-hoc editors for foreign syntaxes that had a basic idea of structure. Like string interpolation or extracting the functions from C source for ren-c. Maintaining a parallel data structure for the types or maintaining a breaking into objects seemed to be a PITA and parse doesn't work so well on object data structures.

I wonder now if instead of strings with context, I actually only needed strings that could be tagged with an associated word, with that word carrying whatever context was required. Using a word instead of binding a context has the possibility of creating a syntax that would allow a string to be saved in a form that includes the word - a bit more homoiconic than a ephemeral context.

Anyway, just a musing... Now back to photos :slight_smile:

3 Likes