oniksan/godobuf

Allow deepcopy of messages

videlanicolas opened this issue · 4 comments

Following #9, consider the following example:

message GiantSlime {}
message PettySlime {}
message MagicOrc {}
message NormalOrc {}

message Slime {
    oneof type_of_slime {
        GiantSlime giant_slime = 1;
        PettySlime petty_slime = 2;
    }
}

message Orc {
    oneof type_of_orc {
        MagicOrc magic_orc = 1;
        NormalOrc normal_orc = 2;
    }
}

message Enemy {
    oneof type_of_enemy {
        Slime slime = 1;
        Orc orc = 2;
    }
}

If one has the following function in GD Script:

const MyProto = preload("res://proto/myproto.gd")
....
func SpawnOrc(spawn_orc:MyProto.Orc) -> MyProto.Enemy:
    var spawn_enemy:MyProto.Enemy = MyProto.Enemy.new()
    var orc:MyProto.Orc = spawn_enemy.new_orc()
    orc = spawn_orc
    return spawn_enemy

spawn_enemy will not contain a copy of spawn_orc, but will instead be empty. The user would have to call the individual set_ function for each property, but will encounter that for composite properties that are defined by messages (like the one in this example) they'll have to initialise a new object and "set" it with the data that comes from spawn_orc.

The API could provide a function to "deepcopy" one proto into another, thus avoiding the need of going each property one by one and setting it to the correct value. An example would be:

const MyProto = preload("res://proto/myproto.gd")
....
func SpawnOrc(spawn_orc:MyProto.Orc) -> MyProto.Enemy:
    var spawn_enemy:MyProto.Enemy = MyProto.Enemy.new()
    var orc:MyProto.Orc = spawn_enemy.new_orc()
    orc.deepcopy(spawn_orc)
    return spawn_enemy

If I understand correctly, you are trying to portray inheritance by means of a protocol, which is not intended for this.
Oneof it's one of unrelated objects.

message GiantSlime {}
message MagicOrc {}

message Slime {
    oneof type_of_slime {
        GiantSlime giant_slime = 1;
        string only_string = 2;
    }
}

message Orc {
    oneof type_of_orc {
        MagicOrc magic_orc = 1;
        sint32 simple_int = 2;
    }
}

message Enemy {
    oneof type_of_enemy {
        Slime slime = 1;
        Orc orc = 2;
        float dog_tail_length = 3;
    }
}

What we need to do??

Perhaps I'm thinking this the wrong way, what I need instead is a library in GD Script that aids protobufs, something like this (in Golang). That way I can have help functions that are common to any protobuf, such as: Merge, DeepCopy, Equals. Would this be the solution here?

I'm not sure... Right now I have very little time to do this project.
Moreover, it is necessary to consider in detail the need for each implemented solution.

Writing this comment for future users that want a similar implementation. I've found a way of doing a deepcopy of one message to another, and is rather simple.

func Deepcopy(from, to):
	to.from_bytes(from.to_bytes())

Given that is short and simple, I don't think we need an extra library to implement this.

Nevertheless there might be more complicated functions that could be needed in the future. Some examples are:

  • Equals(m1, m2, ignore_fields...): Compares messages m1 and m2, if there are repeated fields then the order of repeated elements shouldn't be considered for equality. ignore_fields is a list of keys to be ignored in the comparison.
  • DeepEquals(m1, m2, ignore_fields...): Same as Equals but consider the order of elements in repeated fields.
  • Merge(m1, m2): Merge the contents of m2 into m1, both messages must be of the same type.

Closing this bug since the question has been answered and there' s no need to add a feature.