Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does Rebol really have an equivalent for javascript prototype property?

Gregogy has made a post about rebol and javascript here http://blog.revolucent.net/2009/05/javascript-rebol.html

But as I'm going deeper into comparing javascript and rebol, I can't see what's the equivalent of rebol for javascript prototype. Because extending an object instance from another one with make in rebol isn't exactly like javascript prototype property as js prototype allows to extend ALL instances at once.

So am I mistaken or is there an equivalent of the code below for rebol:

<html>
<head>
</head>

<body>
  <script>        
    function Person(firstName, lastName, sex) {
      this.firstName = firstName;
      this.lastName = lastName;      
      this.whoAreYou = function() {
        alert( "I've been built with Constructor and my name is " + this.firstName + " " + this.lastName);
      }
      this.WhatIsYourSex = function() {
        alert(this.sex);
      }
    };

    Person.prototype.sex = "Man";

  </script>

  <script>
    JaneDoe = new Person("Jane", "Doe");
    JaneDoe.whoAreYou();
    JaneDoe.WhatIsYourSex();
    alert("Are you sure?");
    JaneDoe.sex = "Woman";
    JaneDoe.WhatIsYourSex();
  </script>

</body>
</html>

Update: I don't care about syntactic sugar of course. Nothing prevents extension in R2 by just redefining an object. My question is not about extension of an object INSTANCE but about extension of ALL INSTANCES at once: that's what js prototype property allows.

So to reformulate my question: Can Rebol allow to also extend AUTOMATICALLY ALL INSTANCES of children by extending the parent class like javascript can whatever the syntax I don't care ?

For performance sure I see the difference between R2 and R3 for one instance but as for language functional feature I don't have automatic extension of all children objects which is a big burden as I'll have to manage them myself which will be quite slow since it's not done by the system itself. What if I want to create a framework like jquery which heavily relies on this kind of feature ? It would be a great hassle.

like image 832
Rebol Tutorial Avatar asked Nov 24 '10 22:11

Rebol Tutorial


3 Answers

Oldes is right, the JS-like prototyping is not present in REBOL by default. But you are free to create own functionality that suits your needs. Here is simple example that uses nested context for value sharing between multiple instances to simulate the JS prototyping:

creature: func [
    /prototype
        field [word!]
        value [any-type!]
    /local result proto
][
    proto: [
        context [
            static: context [
                vars: reduce [
                    'kind "Monkey"
                ]
                extend: func [
                    blk [block!]
                    field [word!]
                    value [any-type!]
                    /local pos
                ][
                    either pos: find/skip blk field 2 [
                        change/only next pos :value
                    ][
                        insert/only insert tail blk reduce field :value
                    ]
                    :value
                ]

                get: func [
                    field [word!]
                ][
                    all [
                        field: any [
                            select/skip this/instance field 2
                            select/skip vars field 2
                        ]
                        first field
                    ]
                ]

                set: func [
                    field [word!]
                    value [any-type!]
                ][

                    extend this/instance field :value
                ]

                prototype: func [
                    field [word!]
                    value [any-type!]
                ][
                    extend vars field :value
                ]

                who-are-you: does [
                    print ["Hello I'm" this/get 'kind this/get 'sex this/get 'first-name join this/get 'last-name "."]
                ]
            ]

            instance: reduce [
                'first-name none
                'last-name none
            ]

            ;exported "API"
            get: system/words/get in static 'get
            set: system/words/get in static 'set
            prototype: system/words/get in static 'prototype
            who-are-you: system/words/get in static 'who-are-you

            this: none
        ]
    ]
    unless object? proto/1 [result: reduce proto append clear proto result] 

    if prototype [proto/1/prototype field :value]

    result: make proto/1 []
    result/this: result
]

creature/prototype 'sex "male"


jane: make creature []
jane/set 'first-name "Jane"
jane/set 'last-name "Rebol"

john: make creature []
john/set 'first-name "John"
john/set 'last-name "Doe"

jane/who-are-you

jane/set 'sex "female"

jane/who-are-you

john/who-are-you

creature/prototype 'kind "Human"

jane/who-are-you
john/who-are-you
like image 52
Cyphre Avatar answered Oct 07 '22 08:10

Cyphre


REBOL does not have a equivalent.

An object in R3 is created using any other object as a prototype. But once, created, it is an independent entity. Changes to the object that was used as the prototype will not affect the newer object -- or vice versa.

Objects in REBOL 2, once created, cannot have new fields added to them; all you can really do is create a new object based on the old one, but with new fields. That can be annoying, as it may break references to the old object.

REBOL 3 is much better in that way. extend and append allow new fields to be added to any object.


This script may help a little: link text.

  • It compares an target object to a reference object, and adds any missing fields:
  • It is REBOL 2 code, so the target object gets replaced by a copy rather than extended
  • but it does recurse through any nested objects, so it can make complex nested changes in one pass
like image 33
Sunanda Avatar answered Oct 07 '22 08:10

Sunanda


Rebol Tutorial, your reactions contain too much of "I don't care", don't you think? And by the way, design wise - who on eart came with an idea of a class definition influencing live objects after class instantiation happened? :-)

So - did you actually do any measurements, to compare how slow it is to extend related objects in a loop? Your claim " ... will be quite slow" might show as unsubstantiated.

Let's do some measurements:

obj: context [a: 1] == make object! [ a: 1 ]

dt loop 1'000'000 [append blk copy obj] == 0:00:00.023372

length? blk == 1000000

dt [foreach obj blk [append obj [b: 2]]] == 0:00:02.677348

length? blk == 1000000

blk/1 == make object! [ a: 1 b: 2 ]

blk/2 == make object! [ a: 1 b: 2 ]

blk/1/a: 3 == 3

blk/1 == make object! [ a: 3 b: 2 ]

blk/2 == make object! [ a: 1 b: 2 ]

So, as you can see, I managed to extend 1 million of objects with custom fields in == 0:00:02.677348 time. I am on 4 years old machine. How many of objects your application have?

I know it's not what you probably want, as you have to build list of objects to extend, but it is a starter :-)

-pekr-

like image 40
Petr Krenzelok Avatar answered Oct 07 '22 06:10

Petr Krenzelok