Introduce( []{} )

Functions are about all there is in Copper. This fact is so driven home that, after further consideration, it seems the “fn” is entirely useless. Should it remain?

As it is, functions can be created in four different ways plus an optional way that the interpreter supports:


fn(){}
fn()
fn{}
{}
fn

I decided to replace “fn()” with just simply “[]”. After all, there isn’t any need for the “fn” part when it should be obvious what the variable is storing. Using “[]” would also make code more readable because you wouldn’t be guessing what the parentheses was closing. As it is, parentheses could close either a function header or a function call.
The new syntax would reduce function creation to the following three options:


[]{}
[]
{}

I think this may also lead to fewer mistakes, and it’s easier to type. Here’s what it might look like in practice:


Set_button_callback( [pressed count=int(0)]{
	int_incr(this.count:)
})

The biggest challenge was overhauling the virtual machine to handle this. Forturnately, it didn’t proved difficult. It would have been more difficult to go from not having “fn” to having it.
A number of languages have this syntax, so it’s nothing new. Given that lists are created using an extension with a function call “list()”, making this change would not interfere with list functionality as it would for other languages.
Given that I’m using a repository, I created a new branch to save the old syntax. I usually hate to make breaking changes, but this one definitely seems to be for the better. The main bummers will be having to change all the blog posts I’ve written that use the old syntax, especially the stuff I haven’t posted yet which is already becoming outdated.
I believe I deliberated on this decision some time ago, but that was when I was still working out the details for the language syntax. As it is, it makes perfect sense.
One thing it will help do is to reduce the mistake I keep making in defining functions how every other language does it. It’s a habit that I get from programming in C++ so much.


myFunc(a) {
	print(a:)
}

The above code is actually a function call and an execution body that never gets executed. The function has to be defined first via:


myFunc = fn(a){
	print(a:)
}

Changing the syntax would make it:


myFunc = [a]{
	print(a:)
}

… whereby it would immediately be recognizable if I made the mistake of appending it to the end of the name:


myFunc[a] {
	print(a:)
}

This is still valid code: it creates a variable and a function with a single parameter that isn’t assigned to anything, but in this case, it looks nothing like valid syntax in any other languages I use, so I’m less likely to assume everything is fine. Matlab people may have a problem with it, but this language isn’t designed for them, otherwise I might be using silly operators like “:=” for assignment, among other things.

One of the benefits I’m already seeing is how I myself perceive the syntax. Having “fn” out front always made me think of these function-objects as functions first, then objects. The reality is, the syntax is such that the parameters section is just as important and useful as the body itself. For example, here is a comparison of the old way I was planning to make classes as opposed to the new way:


A = {
	this.toString = { print("class A") }
}
A()

New way:


A = [
	toString = { print("class A") }
]

The former allows for resetting the definition of “toString” back to its original form if it gets erased, but it requires that I call the function in order to create the members. The latter, on the other hand, requires no call, though it doesn’t have a body that allows it to be reset.
Thinking of it this way, it means that it would be very easy to make records using Copper and have all the benefits of a regular programming language.
Of course, I’m sure there are other languages used as such. It seems like languages are usually tailored towards either processing tasks or towards markdown and the overlap is, as in the case of Copper, accidental or cobbled together to add the desired extra functionality.

5 thoughts on “Introduce( []{} )

  1. i almost think its better with fn.

    its not up to me– time will tell. id have to look at a lot of possible (and likely) examples to tell you which one is really better. does the (/will the) language really call for it so much that fn isnt worth typing? if so, take it out. otherwise, it makes it very clear even to someone who has never coded in it “this is a function.” and its just two keys. but its your language, and i mean that sincerely (its very important.)

    Like

    1. I did consider that also, which is why I was hesitant to erase it and I created a second branch in my repo to keep the old syntax. Being an embedded language rather than a general purpose language, I can do that and I’m able to offer both options to users. I usually make optional features into simple macro switches, but this required too many changes in the VM for that, and I see both branches possibly diverging in focus. The “fn” branch, with symbols and numbers in names turned off by default, will probably be tailored to newcomers in programming. The new “master” or “[]” branch (with numbers and symbols in names) will probably be tailored towards more advanced users who might want to use it for things like game scripting and would rather have the speed bonus. (Not using “fn” relieves the VM of several function calls.)

      Liked by 1 person

  2. “Not using “fn” relieves the VM of several function calls.”

    wow, ok interesting. its not a compiler then? dont get me wrong… i can imagine all kinds of ways for *someone else* to optimize something. i never said i would have done it myself 🙂

    Like

    1. Correct, it’s a true interpreted language. It’s probably possible to compile it down to C++, but part of the purpose of the language is to be interactive, so unless I want to invent a JIT compiler, that’s out. That’s not to say I didn’t consider creating two versions of the VM. A version for processing files could be better designed to link with C and C++ libraries, compile to some sort of byte code, not worry about abrupt stream termination, and have its tasks divided into parse trees whose speed isn’t determined by token count, which would make small things like “fn” syntax truly trivial.
      As it is, the fact that not using “fn” relieves the VM of several function calls has to do with just how many calls I make in C++. Function calls don’t necessarily equate to better performance, of course (writing better functions does), but it does provide some tiny time cut that, given how many times you have to use “fn” will add up. 100 uses of “fn” starts to make an impact when you have to make a dozen function calls every time. It sounds silly to argue this when I hit a few keys on my interactive console and watch the computer whip through printing out the names of functions called (and printing to stdout is not a fast operation, might you, in terms of C++ function call speed at least), so my argument could certainly be seen as a stretch. For that reason, I’ve been working on some code to do benchmarks to see just how much speed I’m gaining or losing from different things, such as using commas, using long names, etc. It’s in progress. Stay tuned.

      Liked by 1 person

      1. i shall. and as much as i enjoy hearing about your choices in design, you will surely thank yourself when you decided to provide more documentation and find that a youve already outlined so much of it on your blog. 🙂

        Liked by 1 person

Leave a comment