Roku Developer Program

Join our online forum to talk to Roku developers and fellow channel creators. Ask questions, share tips with the community, and find helpful resources.
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 
jbrave
Channel Surfer

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
Screenshades: The first Screensaver for Roku2!
Musiclouds: The best free internet music, on your Roku!
Ouroborialis: Psychedelic Screensaver for Roku!
0 Kudos
9 REPLIES 9
kbenson
Visitor

Re: understanding scope and m. variables (again)

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).
-- GandK Labs
Check out Reversi! in the channel store!
0 Kudos
jbrave
Channel Surfer

Re: understanding scope and m. variables (again)

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?
Screenshades: The first Screensaver for Roku2!
Musiclouds: The best free internet music, on your Roku!
Ouroborialis: Psychedelic Screensaver for Roku!
0 Kudos
GandK-Geoff
Visitor

Re: understanding scope and m. variables (again)

"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.
0 Kudos
kbenson
Visitor

Re: understanding scope and m. variables (again)

"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()
-- GandK Labs
Check out Reversi! in the channel store!
0 Kudos
Hexamon
Newbie

Re: understanding scope and m. variables (again)

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
0 Kudos
kbenson
Visitor

Re: understanding scope and m. variables (again)

"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.
-- GandK Labs
Check out Reversi! in the channel store!
0 Kudos
TheEndless
Channel Surfer

Re: understanding scope and m. variables (again)

"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
My Channels: http://roku.permanence.com - Twitter: @TheEndlessDev
Instant Watch Browser (NetflixIWB), Aquarium Screensaver (AQUARIUM), Clever Clocks Screensaver (CLEVERCLOCKS), iTunes Podcasts (ITPC), My Channels (MYCHANNELS)
0 Kudos
Hexamon
Newbie

Re: understanding scope and m. variables (again)


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.
0 Kudos
kbenson
Visitor

Re: understanding scope and m. variables (again)

"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.
-- GandK Labs
Check out Reversi! in the channel store!
0 Kudos
Need Assistance?
Welcome to the Roku Community! Feel free to search our Community for answers or post your question to get help.

Become a Roku Streaming Expert!

Share your expertise, help fellow streamers, and unlock exclusive rewards as part of the Roku Community. Learn more.