justinmeza / lci

A LOLCODE interpreter written in C.
http://lolcode.org
GNU General Public License v3.0
784 stars 105 forks source link

LIEK does not perform a deep copy #65

Open lucidBrot opened 4 years ago

lucidBrot commented 4 years ago

I expected LIEK to perform a deep copy of a BUKKIT type'd variable. It seems like it only copies the reference... which means there can only be one instance of my SOCIALCONSTRUCT.

Use Case: Store some state in an object, then duplicate that object in order to keep a backup of the state.

Behaviour: Modifying the copy also modifies the original

Workaround: Create a new BUKKIT (not the specific object, just a generic BUKKIT) and manually copy all the properties. The problem with that is the effort and that functions that would belong to the object have to be generalized.

HAI 1.4

OBTW
    I HAS A [var] ITZ LIEK A [other var]

    Declares a variable and copies the contents of the other variable into the newly created variable. This is only valid if the other variable is a BUKKIT.

    According to https://esolangs.org/wiki/LOLCODE

    But it does not create a deep copy
TLDR

O HAI IM SOCIALCONSTRUCT
    I HAS A PROBBERTY ITZ 100

    HOW IZ I DUPLICATIN
        I HAS A THING ITZ LIEK A SOCIALCONSTRUCT
        THING'Z PROBBERTY R ME'Z PROBBERTY
        FOUND YR THING
    IF U SAY SO

    HOW IZ I CLONINGWEIRDLY
        I HAS A THING ITZ A BUKKIT
        THING HAS A PROBBERTY ITZ ME'Z PROBBERTY
        FOUND YR THING
    IF U SAY SO
KTHX

VISIBLE SMOOSH "Original Property is " AN SOCIALCONSTRUCT'Z PROBBERTY MKAY

BTW CREATE A COPY WITH "LIEK"
I HAS A problem ITZ LIEK A SOCIALCONSTRUCT

BTW CREATE A COPY WITH "LIEK" FOLLOWED BY "R"-ASSIGNMENT OF THE PROPERTY
I HAS A sex ITZ problem IZ DUPLICATIN MKAY

BTW CREATE A COPY WITHOUT "LIEK", SIMPLY ASSIGN THE PROPERTY
I HAS A issue
issue R problem IZ CLONINGWEIRDLY MKAY

VISIBLE "------", VISIBLE ""

VISIBLE SMOOSH "problem probberty: " AN problem'Z PROBBERTY MKAY
VISIBLE SMOOSH "sex probberty: " AN sex'Z PROBBERTY MKAY
problem'Z PROBBERTY R 99
VISIBLE SMOOSH "problem probberty: " AN problem'Z PROBBERTY MKAY
VISIBLE SMOOSH "sex probberty: " AN sex'Z PROBBERTY MKAY

VISIBLE "THE VALUE OF SEX'Z PROPERTY CHANGED! BAD!"
VISIBLE ""

problem'Z PROBBERTY R 88
VISIBLE SMOOSH "problem probberty: " AN problem'Z PROBBERTY MKAY
VISIBLE SMOOSH "issue probberty: " AN issue'Z PROBBERTY MKAY

VISIBLE "THE VALUE OF ISSUE'Z PROPERTY DOESNT CHANGE! GUD!"

KTHXBYE
leyarotheconquerer commented 4 years ago

TLDR: lci doesn't seem to handle Bukkit inheritance quite right. There's a possible workaround (see below).

Explanation

Interesting behavior indeed. I've dug into this a bit and here's what I've found.

I believe lci was patterned after the Lolcode 1.3 proposal for Bukkits, so a rough explanation for how this should work can be found in the archived proposal.

Inheritance / Prototyping

To create an object based upon an existing object:

I HAS A <object> ITZ LIEK A <parent>

Behavior of this sort of inheritance is described further below.

To define inheritance using alternate syntax, do the following.

O HAI IM <object> [IM LIEK <parent>]
  <code block>
KTHX

Inheritance implies a few things, one of which is inheritance of slots (described below). Another thing inheritance does is automatically > create a “parent” slot on the new object. The “parent” slot refers to the object that this object was inherited from, or its prototype. > The parent slot is treated specially by the Bukkit.

...

Assigning a variable within the object first searches for it within the current object. If it has been declared within the current object, then it is set. If that fails, it attempts to access it within the parent object. Search continues in up the chain of parents. If the variable name is found up the inheritance chain, then that variable is declared and created within the current object (where the search started), and the value is set. If the variable search fails and the variable was never previously assigned, then it's a declaration error.

Looking at your example program, it seems that lci is not completely following that last paragraph. It says that "If the variable name is found up the inheritance chain, then that variable is declared and created within the current object". Currently, if the variable name is found up the inheritance chain, then the variable is changed within the parent object.

The code responsible for the assignment is in the updateScopeValue() function. The interpreter shares the same logic for updating nested scopes and Bukkits. Currently, the logic is correctly written for scopes but not for Bukkits. We may need to add Bukkit-specific logic to the function to handle updating inherited fields.

Workaround

In the meantime, the tests in 1.3-Tests/12-Arrays/13-Inheritance/2-Assignment demonstrate a method that might be able to help with your use case. If you want to override the value of a parent's field, you can use the following syntax to set it on the child:

I HAS A parent ITZ A BUKKIT
parent HAS A foo ITZ "bar"

I HAS A child ITZ LIEK A parent
child HAS A foo ITZ "baz"

I HAS A otherChild ITZ LIEK A parent

VISIBLE SMOOSH "Parent:: " AN parent'Z foo MKAY
VISIBLE SMOOSH "Child:: " AN child'Z foo MKAY
VISIBLE SMOOSH "Other child:: " AN otherChild'Z foo MKAY
lucidBrot commented 4 years ago

Thank you for the explanation! That makes sense to me :)

My usecase was to read input into an object with different fields, and then making a copy of that object so that I could have an unmodified copy and a working copy.

Anyway, I have managed to copy without LIEK and finished the adventofcode task I was working on, so I don't need further assistance.

Enjoy the rest of your weekend!