Tag: programming

foreign.run(anytime)

Up to this point, the foreign function system did not allow using callbacks via Engine::runFunctionObject() until after Engine::execute() or Engine::run() (which calls Engine::execute()) had completed. My recent update changes that and makes recursive execution of opcodes easier.

Continue reading “foreign.run(anytime)”

Advertisements

Progress Report #7

Back at it again, this time I’ve made some important bug fixes that have laid hidden since branch Cheetah. Uh oh. Sometimes a bug can be simply reference counting too much, in which case, we call it a memory leak. The major issue, however, was a parsing bug that duplicated variable address names. Hard to believe I missed something as important as that, but it required a certain state of the parser, so I don’t feel quite as bad about missing it. In any case, those are done.

Continue reading “Progress Report #7”

pub: private

A number of languages support a kind of “public”/”protected”/”private” model. The actual implementation and meaning of this model vary from programming language to programming language, but the basic idea remains the same: preventing code outside of an object from modifying certain things inside of it.
As an interpreted language, Copper doesn’t support such a model.

Continue reading “pub: private”

pointer~item

Pointers make using a language easy. Lots of languages exclude stack-based instantiation because the same tasks can be handled by easy-to-create dynamic variables. That said, I couldn’t program normally without them. It’s too annoying. This is one of the fundamental reasons I don’t program in Rust: pointers in Rust are tedious to work with. You have them in a bizarre sort of way, but unless you’re creating router software or other hardware drivers, you may not care about tossing pointers around abit, and your job is usually easier when you can. That said, Copper contains pointers and makes it really easy to make them. I’ve already shown pointers in the syntax tree, so if you read that part, this announcement isn’t surprising. Without further ado, let’s see an example of how to create a pointer. Get ready for one of the shortest lines of legal pointer code you will ever see:

a~b

This line creates two variables, “a” and “b”, and makes “a” a pointer to the function held by “b”. Simple, right? Like Python, if you assign a new function to “b”, “a” no longer points to the same thing as “b”. The difference is that, in this case, the function originally in “b” is destroyed. “a” is left with a pointer to an empty function container, which reports to “a” that the function is gone. Next time “a” tries to access the function, it receives the info that the function is gone, and it promptly drops the container, which is then destroyed when its reference count reaches zero. No side effects. The chain of references is broken because pointers point to a function container rather than the actual function itself.
In fact, technically all variables point to function containers. This makes it easy to convert them into pointers. The only technical difference between a pointer and a non-pointer (as far as the VM is concerned) is that one variable happens to be the “owner” of the function. When that owner drops the container (whether by being destroyed when its stack frame closes or by receiving a new value to store), the container destroys its function and waits for the other pointers to try to access it to receive the news that the function is gone.
There are a couple of nice things about this. First, when a pointer receives the bad news, its variable converts itself to a non-pointer and gains its own unique function. No null pointers, just new data. No crashes. Another nice thing is that, by not holding the function directly, function containers waste very little space. Most of the data – the scope, the parameters, the body etc. – is destroyed by the function that owns them. A huge chunk of memory isn’t being reserved until every last pointer gets the bad news that it’s off limits.
(In case you’re wondering, a~a is also valid, but it just creates a new function.)
One of the other beautiful things about all variables being pointers (to the VM) is that we can easily enforce the syntax rule that all variables are accessed the same way. In other words, the scope-opening token (.) works. No need for a silly arrow (->). The same is true when running a function in a variable that is a pointer. What happens in case of failure? – You get the same thing as if it was a body-less function: an empty function is returned. The language stays consistent.

This

Now that you know about pointers, you might be thinking about the self-reference pointer. C++ has the “this” pointer. Python has a custom-named first-passed parameter (usually named “self”) passed to functions. Other languages have their choice, however convenient or insane they may be named. In Copper, it’s named “this”. It can be used like any other variable.
The role of the self-reference pointer is to allow editing the function-object within the execution body assigned to it. (It’s more like the JavaScript “this” than the C++ one.) The following two things do the same thing:

a.b = 0
a = { this.b = 0 } a()

Notice that, in the second example, the function had to be run. The code within a function is not run automatically. In another article, I’ll show how this is useful for different paradigms.
By “editing the function-object”, what happens is that we edit the persistent scope of the object. What’s that mean? The persistent scope is a group of variables that are members of a function-object. Hence (assuming we have a print function) the following two printed lines are equivalent:

a.out = "hello"
b ~ a
print(a.out)
print(b.out)

The members are unique to the function, not the variable, so if we assign a new function to the variable, all of the old members are deleted along with the old function body, etc.
While members cannot be saved directly, they can be copied with the assignment symbol. Hence, assuming a print function, the following two printed lines are equivalent:

a.out = "hello"
b = a
print(a.out)
print(b.out)

The difference between this and the last example, visually speaking, is the “=” sign. Because this is an assignment operation, the “out” from “b” is a separate variable from the “out” from “a”.

Concluding Remarks

Pointers in Copper are the safest in any language I’m aware of firstly because they are only one type and secondly because they never cause a segfault. I’m aware some people would rather have direct failure, so warning messages are produced. Furthermore, the function are_empty() can be used to check if a function contains no members in its scope, no body, and no return data – which is the kind of function you get if function access fails for a pointer. Again, this may not be desired, and admittedly, Copper is designed for embedding, not large projects, but I intend to do some IDE integration at some point and show how it’s possible to do debugging for this and other bizarre features of Copper.

There is more to pointers than just this, but I’ll save that for another installment.

List and Tuple(1,2,3)

Lists are tuples are very common features for languages. Arrays and lists have been around for some time, so they are almost expected. Python does away with arrays, understandably so, and it almost makes little sense to keep they around for Copper. Tuples, on the other hand, seem primarily for mental models, but can be useful in preventing misuse and accidental deletions or additions of elements as well as providing convenient means for extraction. They sort of fill the gaps for simplicity that lists, arrays, and general objects don’t fill. Both of these should be discussed in detail.

Continue reading “List and Tuple(1,2,3)”

fun fun fn

Functions are essential to any high level language. Without them, it’s very tedious (and error prone) to do anything. They may be disguised in various ways, being referred to as “sub-routines” or initiated using peculiar keywords like “def” and “defn”, but it’s all the same idea. The difference is often power.

Continue reading “fun fun fn”

When To Use Smart Pointers

You could very easily go crazy with smart pointers. It seems like the safe idea, until you realize that you could be tying up memory everywhere. Perhaps you handle them carefully to avoid that issue. A more pressing problem is the mess of code they require to use them, such as is the case if you template your smart pointer class. Even if you are ok with that, your compiler might not be. GCC, for example, has a bug that won’t let you nest templates within each other. Usually you have to create some sort of wrapper class around a template. That makes accessing the data even more tedious.

Continue reading “When To Use Smart Pointers”