Forum Discussion

jbrave's avatar
jbrave
Channel Surfer
15 years ago

understanding scope and m. variables (again)

still trying to understand how scope works in BrightScript.

if in main() I define a var
testvar="test"

then is that variable automatically accessable from a function or a sub by using m.testvar, or do I have to explicitly define it as

sub Main()
m.testvar="test"
end sub

in order to access it from a function or sub?

- Joel

9 Replies

  • Here's a few rules:

    • Functions have separate scopes. - Every variable you use should be defined within the function, passed in as an argument, or accessed from m.

    • Blocks do not have a scope of their own. - Variables defined within a block continue to exist outside that block. Normal for PHP users, different for many other languages. Personally, I find it causes more problems than it helps with me.

    • Only count on globals if using procedural code - m is a handy built-in for accessing globals, but it's overloaded to be used for object attributes as well. Any object oriented code you write will have a hard time accessing those globals, unless you write some wrapper function(s) to access the globals for you.


    To clarify that last point, see the following

    function setFoo()
    m.foo = "bar"
    end function

    function getFoo()
    return m.foo
    end function

    object = {
    foo: "not bar"
    getObjectFoo: getFoo
    }

    ' set global m.foo = bar
    setFoo()

    ' print global m.foo
    print getFoo() ' prints "bar"

    ' print object foo
    print object.getObjectFoo() ' prints "not bar"



    But come to think of it, a more general (but slower) global mechanism would be this:

    function rdglobalGet(name as string) as dynamic
    return m[name]
    end if

    function rdGlobalSet(name as string, value as dynamic) as dynamic
    oldValue = m[name]
    m[name] = value
    return oldValue
    end function


    That should allow global access from anywhere, even within a method (as long as those functions themselves are not turned into methods).
  • jbrave's avatar
    jbrave
    Channel Surfer
    One thing I see in your code and in TheEndless code is these constructions where it appears you are embedding a function call in an roAssociativeArray and giving them a label and then calling them as a method. I don't completely understand this- it seems like It adds an extra level of unreadability to the code but maybe allows you to simplify your code at the same time? Does this stuff execute faster or something?
  • "jbrave" wrote:
    One thing I see in your code and in TheEndless code is these constructions where it appears you are embedding a function call in an roAssociativeArray and giving them a label and then calling them as a method. I don't completely understand this- it seems like It adds an extra level of unreadability to the code but maybe allows you to simplify your code at the same time? Does this stuff execute faster or something?


    He is not putting a function *call* in the roAssociativeArray ("AA" for short), he is putting a function *reference* into the AA. That is, in fact, the way that objects are created in BrightScript; a user-defined object is just an AA with some entries that are member variables and some entries that are methods (function references). ("Native" objects created with CreateObject() are actually C++ objects.)

    BrightScript AA-based objects don't really have classes and inheritance in the classic OO style; they are in this sense somewhat weaker even than JavaScript's object system. Still, they support encapsulation, polymorphism, and namespace control (methods can be defined with inline anonymous function definitions, thus avoiding pollution of the top-level namespace). That's good enough to get a lot of useful work done.
  • "GandK-Geoff" wrote:
    "jbrave" wrote:
    One thing I see in your code and in TheEndless code is these constructions where it appears you are embedding a function call in an roAssociativeArray and giving them a label and then calling them as a method. I don't completely understand this- it seems like It adds an extra level of unreadability to the code but maybe allows you to simplify your code at the same time? Does this stuff execute faster or something?


    He is not putting a function *call* in the roAssociativeArray ("AA" for short), he is putting a function *reference* into the AA. That is, in fact, the way that objects are created in BrightScript; a user-defined object is just an AA with some entries that are member variables and some entries that are methods (function references). ("Native" objects created with CreateObject() are actually C++ objects.)

    BrightScript AA-based objects don't really have classes and inheritance in the classic OO style; they are in this sense somewhat weaker even than JavaScript's object system. Still, they support encapsulation, polymorphism, and namespace control (methods can be defined with inline anonymous function definitions, thus avoiding pollution of the top-level namespace). That's good enough to get a lot of useful work done.


    The main benefit we use it for is encapsulation.

    A classic (and my personal favorite) example is a coordinate system. Here's how we can use this to model points and use the points to model a line.


    function newPoint() as object
    point = {
    x: 0
    y: 0
    setX: function(x as integer)
    m.x = x
    end function
    setY: function(y as integer)
    m.y = x
    end function
    set: function(x as integer, y as integer)
    m.x = x
    m.y = y
    end function
    toStr: function()
    return "("+m.x.toStr()+","+m.y.toStr()+")";
    end function
    }
    return point
    end function

    function newLine() as object
    line = {
    p1: invalid
    p2: invalid
    setStart: function(p as object)
    m.p1 = p
    end function
    setEnd: function(p as object)
    m.p2 = p
    end function
    toStr(): function()
    return "line from "+m.p1.toStr()+" to "+m.p2.toStr()"
    end function
    }
    return line
    end function

    point1 = newPoint()
    point1.setX(2)
    point1.setY(4)
    print point1.toStr() ' prints "(2,4)"

    point2 = newPoint()
    point2.set(9,11)
    print point2.toStr() ' prints "(9,11)"

    otherpoint = newPoint()
    ' newPoint() just returns an associative array
    otherpoint.x = 10
    otherpoint.y = 20
    print otherpoint.toStr() ' prints "(10,20)"

    line1 = newLine()
    line1.setStart(point1)
    line1.setEnd(point2)
    print line1.toStr() ' prints "line from (2,4) to (9,11)"



    As you can see, each associative array is a self contained chunk of both data and methods to work on that data, or in CS parlance they are "objects."

    P.S. The code above is a bit short on sanity checks to ensure the correct things are passed into the methods. Also, I'm a fan of returning m from methods so I can chain them, like point.setX(1).setY(5).setZ(4).vectorize()
  • Excellent idea! Here's a bit more generalized version for creating pseudo-globals for something like global config options and don't want to turn the entire app into a pseudo-object (which is a good idea but geeks be lazy):


    Function constructConfig()
    m["config"] = createObject("roAssociativeArray")
    End Function

    Function getConfigValue(key as String) as Dynamic
    config = m["config"]
    return config[key]
    End Function

    Function setConfigValue(key as String, value as Dynamic)
    config = m["config"]
    config[key] = value
    End Function
  • "Hexamon" wrote:
    Excellent idea! Here's a bit more generalized version for creating pseudo-globals for something like global config options and don't want to turn the entire app into a pseudo-object (which is a good idea but geeks be lazy):


    Function constructConfig()
    m["config"] = createObject("roAssociativeArray")
    End Function

    Function getConfigValue(key as String) as Dynamic
    config = m["config"]
    return config[key]
    End Function

    Function setConfigValue(key as String, value as Dynamic)
    config = m["config"]
    config[key] = value
    End Function


    Yeah, we were planning on doing something for the RokuDev library, but never got around to it.

    Have you tested that? I think I discovered that the global object was actually unique to each function (but it's been a while since I tested and I don't remember). Less like a global mechanism and more like a way to implement Singletons. If that's the case, getConfigValue and setConfigValue are working with different "m" objects, but you can still do it by creating a combined get/set function.
  • "kbenson" wrote:
    Yeah, we were planning on doing something for the RokuDev library, but never got around to it.

    Have you tested that? I think I discovered that the global object was actually unique to each function (but it's been a while since I tested and I don't remember). Less like a global mechanism and more like a way to implement Singletons. If that's the case, getConfigValue and setConfigValue are working with different "m" objects, but you can still do it by creating a combined get/set function.

    That's not been my experience. I usually create a global Configuration object in RunUserInterface(), and access it throughout my application by calling Configuration().GetValue/SetValue where Configuration() is:

    Function Configuration() As Object
    Return m.Configuration
    End Function

  • Yeah, we were planning on doing something for the RokuDev library, but never got around to it.

    Have you tested that? I think I discovered that the global object was actually unique to each function (but it's been a while since I tested and I don't remember). Less like a global mechanism and more like a way to implement Singletons. If that's the case, getConfigValue and setConfigValue are working with different "m" objects, but you can still do it by creating a combined get/set function.


    So far appears to be working from various scopes (functions that is). I'll update the post if I see any problems with it.
  • "Hexamon" wrote:

    So far appears to be working from various scopes (functions that is). I'll update the post if I see any problems with it.


    Ah, I'm probably mis-remembering the results of my testing then.