Question

Instead of creating objects by writing:

obj: object [
    name: "Fork"
    id: 1020
]

I'd like to write something like...

obj: something-or-another [name id] ["Fork" 1020]

...and get the same result. An ideal solution would also permit:

obj: something-or-another [name: id:] ["Fork" 1020]

Easy enough to write a something-or-another, but does this fit something already "in the box"?

Was it helpful?

Solution

I don't believe there's a baked-in way to do this. Not difficult though:

func [words values][
    set words: context append map-each word words [to set-word! word] none values
    words
]

I suppose I could break this down a little:

func [
    "Creates an Object From a Block of Words, Assigns Values"
    words [block!] "Words used to create object"
    values "Value(s) to assign"
][
    words: map-each word words [to set-word! word] ; The requisite set-words
    append words none ; Initial value for all words
    words: context words ; Create our object
    set words values ; Assigns our value(s) to the object
    words ; returns the object
]

You might employ a different method to interleave blocks, such as:

func [words [block!] values [block!]][
    collect [
        repeat index max length? words length? values [
            keep words/:index
            keep values/:index
        ]
    ]
]

OTHER TIPS

Here's something that requires at least Rebol 3:

func [
    "Create an object based on some words and values."
    words [any-word! block!] "Word or block of words"
    values [any-type!] "Value or block of values"
    /local object
][
    object: make object! either block? words [length? words] [1]
    set bind/copy/new :words object :values
    object
]

If you want to also allow setting unset values, try this:

func [
    "Create an object based on some words and values."
    words [any-word! block!] "Word or block of words"
    values [any-type!] "Value or block of values"
    /any "Allows setting words to any value, including unset"
    /local object
][
    object: make object! either block? words [length? words] [1]
    apply :set [bind/copy/new :words object :values any]
    object
]

Both of these create objects with self, so if you want to create an object without self you have to do some fancier tricks. See the selfless proposal for details.

I wrote a similar function (Rebol2) just a few days ago:

build-object: func [
    "Builds an object from a block"
    names [block!] "Field names"
    /values val [block!] "Initial values"
    /local o name value
] [
    o: copy []
    names: compose names
    o: either values [
        parse names [
            some [
                set name [word! | set-word!]
                (append o to-set-word name)
                | skip
            ]
        ]
        set/pad reflect o: context append o none 'words val
        o
    ] [
        if any [
            parse names [
                some [
                    set name [word! | set-word!]
                    (append o reduce [to-set-word name none])
                ]
            ]
            parse names [
                (clear o) some [
                    set name [word! | set-word!] set value any-type!
                    (append o reduce [to-set-word name :value])
                ]
            ]
        ] [context o]
    ]
    o
]

To build your object you could write any of: (create a function as f: does ["x"])

  • build-object [name "Fork" id 1020]
  • build-object [name: "Fork" id: 1020]
  • build-object/values [name id] ["Fork" 1020]
  • build-object/values [name: id:] ["Fork" 1020]
  • build-object [name f]
  • build-object [name (f)] ;block is composed
  • build-object [name 5 id f]
  • build-object [name 5 id 'f]

You can also make objects with fields set to none if you leave the values out, e.g. with

build-object [name id]
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top