Declaring variables in loops and concatenating function outputs inline

Two things that don’t appear to work that would be a big time saver in scripting: the ability to declare a variable inside a for loop, and the ability to call a function inside a print command and append text to it. As it is now, declaring a readable print command is hella painful, especially inside a for loop. I have to declare variables for every function who’s output I want to include in my print command, then print. Or if my print is inside a loop, add ANOTHER step of then assigning those variables inside the loop before printing. This is impressively inefficient.

So instead of writing:

Var i: Int
For i = 0; i < Size(mBlock); i = i+1 Do
    Print("Is " + GetPluginCaption(mBlock[i]) + " bypassed? " + IsPluginBypassed(mBlock[i]))
End
Var i: Int
    bypassed: String
    caption: String
For i = 0; i < Size(mBlock); i = i+1 Do
    bypassed = IsPluginBypassed(mBlock[i])
    caption = GetPluginCaption(mBlock[i])
    Print("Is " + caption + " bypassed? " + bypassed)
End

That’s 4 extra lines of code. Am I missing something here? I want to believe I’m just stupid. (Also, seems I can’t declare ‘i’ at declaration of the loop? Again, unless I’m missing something syntactical.)

Thanks,
-M.

I’m not at my computer to test, but I’m surprised if you’re saying you can’t get your first code block to work. I do that sort of thing all the time. Are you getting a specific compilation error?

Aww hell, it might’ve been me on this one!

Wait, no, here it is:

Whatever (Rackspace) - Semantic error in “Main”: Line 30, Col 43: Whatever (Rackspace) - Semantic error in “Main”: Line 30, Col 43: Types are not compatible

Okay, weird conditions: if the command is “GetPluginCaption”, it all works. If command is “IsPluginBypassed”, then the first thing in the print block must be a string. So, this works:

Print(GetPluginCaption(mBlock[i]) + " bypassed? " + IsPluginBypassed(mBlock[i]))

and this works:

Print("Is" + IsPluginBypassed(mBlock[i]) + " bypassed? ")

But this doesn’t:

Print(IsPluginBypassed(mBlock[i]) + " bypassed? ")

Because the 1st expresssion is boolean and you cannot concat boolean + string.

1 Like

Yep, that’s my experience. Quick solution is to put “” as the first thing in the print. Or use the specific “ToString” functions.

Print(“” + …

BoolToString : Returns a string representation of a boolean value

  • Declaration: function BoolToString (b : boolean) Returns String
  • Category: Strings
    Parameters * b : boolean
  • returns String
2 Likes

:man_facepalming::man_facepalming::man_facepalming::man_facepalming::man_facepalming:

A short moderator’s remark…

I think, it is always a good idea to choose your words carefully. You could also have doubted your own basic knowledge of programming languages before doubting the efficiency of GPScript. The developer of GPScript holds a PhD in programming languages, so there is little chance that GPScript could be “impressively inefficient”. Of course GPScript is perfectible and continues to improve with constructive feedback from users which is always appreciated and encouraged :wink:

1 Like

This leads me to believe that you’ve tried many scripting and other programming languages. Which ones are you most proficient in that are less “inefficient”? Maybe we could take a look and reevaluate some things. I assume by “inefficient” you’re not referring to the performance, but rather to something else - what exactly?

As you realized - this is not true and you can use returns of functions directly in the print statements or elsewhere as long as the return type is string or at least something that can be safely converted to a string (although I’d not allow anything but strings and require implicit conversion).

Why is declaring a variable outside the loop “less efficient”?

No, you don’t!

No, you don’t!

Thank you. Your opinion fills a much needed gap!

What exactly is weird about this — GP Script is strongly typed.

Fair enough. I was being an ass. It was late and I was frustrated. A round of apologies on me.
When I said inefficient, I mean in terms of the programmer’s time/economy of code, not execution time. So further apologies if that was unclear.

And yes, I have actually used quite a number of scripting languages. Mainstage makes use of a custom javascript implementation, and while it’s not the most up to date ECMAScript, it’s very powerful, fast and convenient. The fact that it’s object oriented allows me to accomplish things much more efficiently.

Other examples: both Cinema 4D and Houdini make use of python as their scripting language. Again, object oriented, and very fast and easy. Python even has some very human readable syntax, which is convenient if you’re looking to implement something easy for musicians with varying levels of code experience (or even interest). The best part is your code reference can focus on your built-in data types, without the need to teach programming basics, or explain any unusual syntax. Users can look at any number of python references online, as opposed to trying to look up Pascal references that may or may not apply. The bounty of useful python info online is hard to overstate.

An example of an issue where a procedural language like this is cumbersome:

I’m making a script that activated and deactivates different groups of MidiInBlocks. How I’d like to achieve this would be to define InstrumentSet objects that have a method for bypassing or unbypassing all of their given MidiInBlocks. I could take this one step further and have the “turn on” method of any given InstrumentSet also call the “turn off” method of all other InstrumentSets. Then I can use one command to both activate one set, and deactivate all others. (As long as we’re talking wishlist, the best would be a file in which I could define some boilerplate I use frequently, so it’s available in all scripts. Mainstage has this too, though it was a bit of a hack.)

Currently instead I’m defining instrument set arrays and using “turn on” and “turn off” functions with for loops that unbypass or bypass all the instruments of a given instrument set, respectively. I could define another array of instrument set names that the “turn on” function could then loop through and call the “turn off” function on, though to check against the array of names I will have to also pass the instrument set name to the “turn on” function as a string in addition to the instrument set array itself. Unless there’s a function that returns the name of an array? That also requires me making an extra array and retyping all the instrument set names as strings.

And declaring variables outside a loop and then assigning them inside instead of just declaring and assigning them in a single line is less efficient economy of code. That’s two lines instead of one for every variable to which I might need to assign data that makes use of ‘i’.

Anyway, sorry again for being an ass. But I really do have a wealth of experience with different coding languages in different scripting contexts, and while I appreciate the intention of making GPScript beginner friendly and simple, I’m not a fan of the choice to use a procedural language, or anything that makes me use more code than necessary.

And, apologies for any rudeness in that critique. I really do appreciate GigPerformer and all of the yard work that goes into making it.

:rofl: Hard work. But dealing with people like me may be more like yard work, I suppose.

(NB the following is not intended as “defensive” but rather just a summary of why GP Script is the way it is)

GPScript is not aimed at developers and it is certainly not going to complete with languages that have been around for 25 (Javascript) or 30 (Python) years and that have gone through many iterations throughout their development, particularly since GP Script is just a small piece of Gig Performer and something that most users don’t even need to touch, particularly with the addition of scriptlets that can be downloaded.

The goal of GP Script was to make it easy to do simple things like respond to and modify an incoming MIDI message or respond to someone turning a widget. I looked at languages like Javascript and puked at the concept of a language that

  1. interprets ++[[]][+[]]+[+[]] as the string “10” (try it) or
  2. languages confuse functions that you call with functions that are really callbacks but look just the same or
  3. languages that allow one to mix/match different data types - the source of many obscure bugs.

The downside of using other existing languages (such as Lua or Python) was that we would have to do the equivalent of pushing a square peg into a round hole making the resulting code rather inelegant.

Writing
On ControlChangeEvent(m : ControlChangeMessage) Matching [7..10] from AkaiSurface
is a heck of a lot cleaner than what you would have to write in any of those other languages. Further, it can’t be called by mistake, etc.

Sure, objects would be nice and maybe in GP 2 or GP 3, we could add such things but I’m not sure it’s high priority relative to other functionality, same for declaring a variable inside a for loop, particularly as one of our goals is for GPScript to be as unnecessary as possible for regular musicians.
(I wonder what percentage of MainStage users actually use that Javascript stuff — I bet it’s a tiny number).

That said, now that Gig Performer has an external API, there’s nothing to stop a motivated developer from created an extension that connects the GP functionality to a Python or (god forbid) Javascript interpreter. In fact, I 'm waiting for someone to create an external that integrates PDLib (the Pure Data runtime) into Gig Performer, that would be really cool.

…and GPScript is compiled and not interpreted. :+1:

I think it really comes down to an understanding of the goals and implementation of any computer language. GPScript is really statically typed (and compiled accordingly). There are a significant number of statically typed, dynamically types and in one case, a 'promiscually typed" language in the wild.

Understanding the typing of a language is foundational to the understanding of the language as a whole. That being said, thanks for always challenging the status quo.

X

1 Like

@dhj you mention an “external API”, but while I could find mention of this in the GP documentation, I’ve not been able to find more specific information, such as which programming languages it can interface with, API function documentation and the like. Do you know if this information is available to us mere mortals?

I am getting an “Unknown Identifier: GetPluginCaption” message using the following script:

var
MyString : String
initialization
MyString = GetPluginCaption(Instrument_2)
end

“Instrument_2” is the handle for the plugin block:

Please give me an example of how to use “GetPluginCaption” correctly.

You have to declare all plugins and widgets in the initial variables section.

Instrument_2 : PluginBlock

1 Like

It was already declared in the Rackspace Script:

You can’t declare this in the Scriptlet however.