Floating Objects

Floating new objects are those things you create on the heap and then toss around your program as if they weren’t tied to any particular location. It’s nice to delegate the job of specific object creation to some function and have it return the packaged data with a special interface for accessing only the parts we need. … Or in other words, object factories. Object factories require the heap.

Creating objects on the heap is something static languages tend to handle with the “new” keyword whereas dynamically-typed languages tend to automatically put everything there. The Copper VM allocates on the heap, but because it doesn’t allow for persistent data via pointer reference counting, it would seem rather difficult to create data in a random function and have it remain intact even after leaving that function. Well… yes and no.

In Copper, it is perfectly acceptable to return a function that will, in effect, contain copies of all its contents to a lower stack frame.

NOTE: This functionality is available for all branches of Copper. The only difference is function declaration syntax

A = {
 a = 5
 ret( fn(a=a) ) # ret([a=a]) for other branches #
}

B = {
 a = A()
}

One problem is that if the data is stored in a temporary variable, the data will be destroyed when the stack frame is destroyed. Saving pointers to that data will do nothing. You can return that data from the function. You can copy that data by saving it to other functions. But you can’t create a unique object and move it around at will. This is a bit of a problem if you want a unique object. It would appear that the only solution to this problem is by having a chain of persistent scopes that trace their roots back to the global scope.
The following is such a chain:

a = {
 this.a = {
 this.a = A()
 }
}

This is NOT such a chain:

b = {
 b.b = {
 this.b = A()
 }
}

The test for having such a chain is if all of the variables can be accessed by stringing them together in a membership chain. The above examples would look like this:

a.a.a.a (Passes test)
b { b.b.b } (Fails test)

Remember, the variable limitations are designed to handle lifetimes in a reliable way. That said, whenever you work with variables, you should think about the primary storage variable as being devoted to lifetime management. It’s easy to create pointers, and you always have a target where pointers can be reset just in case they lose the data somehow.

Of course, it would be tedious for programmers to concentrate on designing their systems perfectly. Part of the purpose of Copper is to make less work, not more. The task of handling variables would be much easier if you could have one variable steal the ownership of a function from another variable. You can do this with the “own” control structure. It looks like a function that takes a name (or chain of member names) as an argument: The variable that claims ownership.

b = {}
a~b
own(a)

In the earlier example, the chain could be remedied by using this ownership control structure.

b = {
 b.b = {
 this.b = A()
 }
 b.b()
 this.b~b.b
 own(this.b)
}

Of course, if the variable does not exist, nothing happens with regard to the change of ownership.

WARNING: Changing ownership can result in cyclic loops in memory that prevent the destruction of objects and deallocation of memory. Therefore, by default, this feature is disabled in the virtual machine. It’s better if you just work with the language as it’s meant to be and use the “own” control structure sparingly. At least you won’t be stuck should you ever need to change an object’s ownership.

Why Own?

The primary reason for the “own” structure in Copper is for situations where you have tons of data associated with the lifetime of a variable and you want it to be moved to a new variable but not copied. Pointing to the data isn’t always suitable because the data may be from a kind of generator and saved in an intermediate object whose sole purpose is to receive new functions, not save old ones.
There may be a few other legitimate use cases of the “own” structure, but like most languages, it is possible to avoid the corner cases by changing how you perceive you ought to code in the language. Given how different Copper is from other languages, this is a natural extra requirement and shouldn’t be too much to ask.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

w

Connecting to %s