Copper is a language dictated by many, many parentheses. In other languages, you may get accustomed to throwing parentheses wherever you need them. In Copper, the rules are strict.
To do just about anything, you have to make a function call. Calling functions, getting data, printing data, and so forth, all requires function calls. For basic Copper, this results in quite a few parentheses. The prevalence of parentheses means that you can get a thick forest of them really quick. Copper is like LISP in that sense.
Being that there are so many parentheses with such a loose syntax language, certain things cannot be allowed. One of those is that there are no free parentheses. Parentheses can only be used for function calls. Without it, you would have ambiguous code, as in the following:
a = b
This is function call to “b”, even though it is on a separate line. That makes something like this a very easy mistake to make.
Not having independently-acting parentheses (that is, parentheses that group operations) seems anti-pattern at first, but the fact is, Copper doesn’t need such a feature. Most things, including data, terminate immediately. Even if you had the feature of independently-acting parentheses, what would you use them for? There is no built-in math system, as I’ll discuss later. Square brackets could be used for function calls or for the operation grouping, but again, the feature is needless.
There are other techniques to improve visual clarity.
One technique I have just recently implemented is a shorthand for function calls. There are tons of parameter-less function calls going on just to get data. After writing out some mini programs, I noticed it was really easy to accidentally hit the parentheses buttons in the wrong order as I tried to speed type. (And as I wrote this article, I discovered how easy it is to forget to type “n” in “parentheses”.) Furthermore, it is very easy to forget or skip adding them (“until later”) out of laziness. This is alarming since it means simple bugs can easily creep into user programs just because things are too verbose. On top of all that, the number of parentheses showing up everywhere made some function calls rather crowded. Even with syntax highlighted, I wanted less clutter so I could see what was going on.
Introducing the “immediate-run” token: … :
Yes, it’s the colon.
Here’s the difference it makes for a simple function call:
sum(a() b() c())
sum(a: b: c:)
Three key strokes, more clarity (that is, if you still consider using a colon readable, understandable syntax for this language). While the top one is still easy to read, function names tend to be alot longer and many of them are nested in other function calls and combined with variables of smaller names.
Using a single character as a special token doesn’t solve the clutter problem entirely. Part of the issue must be resolved by other means. This is especially the case with mathematics. Part of the clutter issue can also be solved be changing the way the user programs. Splitting operations into multiple parts and saving to variables makes the code more readable. The code may run a wee bit slower, but if speed is your concern, you probably shouldn’t be using an interpreted language to begin with.
Admittedly, the immediate-run token feature does complicate the syntax alittle, which is unfortunate. I would like to avoid that, but as it isn’t doing something unique nor removing or replacing something useful, it barely squeezes in as being acceptable.
~ Why no automatic deduction / function calls? ~
There is the possibility that I could have data be extracted from functions when passed to functions. This obviously doesn’t make sense for user-defined functions (because the user may actually wish to pass the function itself and make a pointer to it, regardless of the current function contents) but, at first glance, it might make sense for system or extension functions.
There are a couple of problems with this approach. First, the general user doesn’t necessarily know what is and isn’t a system or extension function. Admittedly, they may know all the built-in functions (there aren’t very many), but extension function names may not be known. Consequently, they won’t necessarily take advantage of that feature. It adds unnecessary burden on anyone reading the code because it makes function call semantics inconsistent. Finally, implementing such a feature may mess up code that performs the function call by-the-book.