how to copy an object?

This is driving me nuts...

I like to simply copy an object:

class MO2Data {
    var front_tyre_pressure;
    ...
}

class MuscleOxygenDataPage {
    function parse(payload, data) {
        var data_old = data; // <-- this one does a reference only
        data.front_tyre_pressure = payload[1] * 0.05;
        ...
        if (!data_old.equals(data)) {
	        System.println( "update display" );
        }
    }
}

There is no copy example in the documentation and even Google does not know about "Monkey C copy".

Can anyone help?

  • You can't do this directly like you are hoping. Unless you implement equals, you can't compare objects like that either (the default equals implementation just compares the object references, not the values).

    In this case, it seems the right solution is to not make a copy at all. You should be able to allocate a clean object and initialize it with the information from the payload, and then compare the results.

    class MuscleOxygenDataPage {
        function parse(payload, data) {
    
            var new_data = new MO2Data();
            new_data.front_tyre_pressure = payload[1] * 0.05;
            ...
            if (!new_data.equals(data)) {
    	        System.println( "update display" );
            }
        }
    }

  • Thanks for the info, but the proposed solution will not work. I get a new payload every 250 ms and need to compare it to the current data. The new payload needs to be decoded and returned in the var data.

    I'll try s.th. different and have two preallocated variables and store the decoded results alternating in both.

    I'm surprised someone invents a language without a copy operator...

    Thanks for your time.

  • While it isn't wrong, but it seems very weird to return data via a function parameter in MonkeyC. Is there some reason you can't just return the parsed result from the parse method?

    If you really need to use data as an output parameter you could write a routine to do a copy. I think these would work for the built-in types.

    function deep_copy(input)
    {
        var result = null;
    
        if (input == null) {
            // do nothing
        }
        if (input instanceof Lang.Array) {
            result = [ input.size() ];
            for (var i = 0; i < result.size(); ++i) {
                result[i] = _recursive_deep_copy(input[i]);
            }
        }
        else if (input instanceof Lang.Dictionary) {
            var keys = input.keys();
            var vals = input.values();
    
            result = {};
            for (var i = 0; i < keys.size(); ++i) {
                var key_copy = _recursive_deep_copy(keys[i]);
                var val_copy = _recursive_deep_copy(vals[i]);
                result.put(key_copy, val_copy);
            }
        }
        else if (input instanceof Lang.String) {
            return input.substring(0, input.length());
        }
        else if (input instanceof Lang.ByteArray) {
            result = input.slice(null, null);
        }
        else if (input instanceof Lang.Long) {
            return 1 * input;
            
        }
        else if (input instanceof Lang.Double) {
            return 1.0 * input;
        }
        else {
            // primitive types (Number/Float/Boolean/Char) are always copied
            result = input;
        }
    
        return result;
    }
    
    function shallow_copy(input)
    {
        var result = null;
    
        if (input == null) {
            // nothing
        }
        if (input instanceof Lang.Array) {
            result = [ input.size() ];
            for (var i = 0; i < result.size(); ++i) {
                result[i] = input[i];
            }
        }
        else if (input instanceof Lang.Dictionary) {
            var keys = input.keys();
            var vals = input.values();
    
            result = {};
            for (var i = 0; i < keys.size(); ++i) {
                result.put(keys[i], vals[i]);
            }
        }
        else if (input instanceof Lang.ByteArray) {
            result = input.slice(null, null);
        }
        else {
            result = input;
        }
    
        return result;
    }
    

  • Thanks for this elaborate code example!

    I started my app based on the MO2Display example. This example uses the return via function parameter syntax.

    What I find way more weird, is that "primitive" types _are_ copied, while others aren't. The documentation states _everything_ is an object... With a background of solid C++, it's very difficult for me to understand the design of the language.

    Thanks for sharing your code. This definitely helps me understanding more of the language.

    Best regards,
    Sebastian

  • What I find way more weird, is that "primitive" types _are_ copied, while others aren't. The documentation states _everything_ is an object... With a background of solid C++, it's very difficult for me to understand the design of the language.

    This was a design decision, and it isn't documented all that well.

    As you probably already know, MonkeyC uses reference counting to ensure that objects are automatically cleaned up when no longer referenced. This reference counting system is composed of a handle class exposed in MonkeyC as a var/const (essentially a type flag and a pointer), and then a body class which is internal to the VM (the actual object data).

    Primitive objects like Boolean, Number, Float, Char are are small enough that they can fit into the pointer portion of the handle without doing a heap allocation for them. The VM uses this to reduce heap usage. Most applications don't notice any negative side-effects from this, and the heap savings is quite noticeable.