5

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"?

3 Answers3

3

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
        ]
    ]
]
rgchris
  • 3,698
  • 19
  • 19
  • The first of your code examples (the function might need a name) is short and clean and it looks as the best to me. – Ladislav Aug 21 '13 at 07:52
2

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.

BrianH
  • 2,186
  • 16
  • 14
1

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]
endo64
  • 2,269
  • 2
  • 27
  • 34
  • Interesting that it would come up more than once in a short period! Maybe a sign that it comes up often, and something here should be standardized. Is there a reason to express your `values-rule` like that as opposed to a `difference` from `any-type!`? – HostileFork says dont trust SE Aug 21 '13 at 17:13
  • It was for my special need. But you're right, using any-type! could be useful. – endo64 Aug 22 '13 at 10:45
  • I wrote another version using any-type and some small fixes, should I edit my previous answer or add a new one? – endo64 Aug 22 '13 at 10:48
  • Cool. Generally I think it's best to edit the answer...(note that the edit history is available so if anyone is ever confused about the comments they can roll back and see the old version.) – HostileFork says dont trust SE Aug 22 '13 at 17:53
  • Ok, thank you, I've updated the function and added more examples. Note that the given block is COMPOSEd first and then REDUCEd. Examine the following example: `probe build-object [a 1 b 3 c (f) d a e f]` – endo64 Aug 23 '13 at 11:33