Universal Robots Forum

Issue with URScript scoping

I’m working on a URScript file. I’ve been running into issues with scoping. In particular, if you try to run a function like the one here:
def myProg():
a = 0
def myFun():
popup(a)
end
end

a compile error will appear saying that ‘a’ is not defined. The only way around this I’ve found is to indicate that ‘a’ is global (“global a = 0”), however this pollutes the global namespace. Is this expected, a bug, or am I just doing something wrong?

I’m running version 3.4.1.59

Thanks

1 Like

You need to indent your file. I wrote this as a script inside of a Polyscope program and this is the script output and it runs without any issues. Notice how the file is indented though.

def test_function():
set_standard_analog_input_domain(0, 1)
set_standard_analog_input_domain(1, 1)
  set_tool_analog_input_domain(0, 1)
  set_tool_analog_input_domain(1, 1)
  set_analog_outputdomain(0, 0)
  set_analog_outputdomain(1, 0)
  set_tool_voltage(0)
  set_input_actions_to_default()
  set_tcp(p[0.0,0.0,0.0,0.0,0.0,0.0])
  set_payload(0.0)
  set_gravity([0.0, 0.0, 9.82])
  rtde_set_watchdog("speed_slider_mask", 10.0, "pause")
  while (True):
    a=23
    def myFunc ():
      popup(a)
    end
    myFunc()
    halt
  end
end

I took out the lines in the file that show what is printed in Polyscope to make it a bit easier to read.

@mbush Thanks for the response, however that’s not my issue. The code is indented in my script file (I tried both 2-space indent and 4-space indent). But I don’t think URScript is strict about indentation anyway.

I’ve attached a screenshot of my .script file and the resulting error

.

By the way, how do you do the code formatting? Clicking the </> button up top doesn’t seem to work right.

Also, @mbush, after I tested doing the same thing via Polyscope, I think you’ll find that the Polyscope defined your variable ‘a’ as a ‘global’ variable, something I am specifically trying to avoid (in the case one of my users unsuspectingly redefines a variable!)

1 Like

So doing some testing what I find is if I write the code similar to what you have above that I have to pass in the variable to the function as shown below then code runs as expected and the popup shows 23 and all is good with the world, however…

def myOuter():
  a=23
  def myFunc (b):
    popup(b)
  end
myFunc(a)
end

If my user then declares a variable called ‘a’ and assigns it a value my function will 1) not alert them that the variable already exists and 2) will override any value they enter and set the new value to my value which could cause unintended side effects for the end user and leave them trying to figure out where this is coming from. If your script is being generated in a URCap this could be very difficult for the average user to find the root cause.

Notice that below the variable is being assigned 10 by the program but my function is overwriting that to a value of 23 which is probably not the desired behavior.

IMO it’s better to use the local keyword in front of any variable that I do not want the end user to be able to affect nor that I want to cause to be affected

def myOuter():
  local a=23
  def myFunc (b):
    popup(b)
  end
myFunc(a)
end

Notice that the variable a listed in the variables tab maintains the value that I assigned to it.

It doesn’t really make it a global variable in that, if you run the code you will notice that it is not in the variables list. However, if you put the keyword global in front of the variable it will then show up in the list and expose it to the user. However, I do agree that it is not protected and if the end user defines a variable named the same then this one will be overwritten or should they happen to know it exists then they could use it for other purposes as well.

The passing the parameter function is fine, albeit clunky, except in this kind of case:

def myOuter():
    a = 23
    def myFunc():
        a = a + 1
    end

    loop_cnt = 0
    while loop_cnt < 10
        myFunc()
        loop_cnt = loop_cnt + 1
    end
    popup(a) #should return 33
end

In otherwords, I want my nested functions to be able to update the variables in the scope above it. Now of course we could do something like this (where the ** lines are the changes)

def myOuter():
    a = 23
    def myFunc(b):
        **b = b + 1**
        **return b**
    end

    loop_cnt = 0
    while loop_cnt < 10
        **a = myFunc(a)**
        loop_cnt = loop_cnt + 1
    end
    popup(a)
end

However, I might not want to return that value (could just be a counter, for example) but something else more useful. So if the answer is the scoping behavior documented here is expected, and we just have to hack around it, I’ll accept it. But it just feels like I’m doing something wrong or this is a bug.

@paul.weidinger I could also use “static” variables (i.e. variables that live inside a function and keep its values from one function call to the other) to keep an internal state of a function, but without polluting the global variables. Did you find a workaround for this?

No I did not. I’ve just been passing variables around.