Reflection and Meta-programming

Since the Ring programming language is a dynamic language, we can get answers about the program code and we can modify our code during the runtime.

In this chapter we will learn about this and the available functions to use.

  • locals()

  • globals()

  • functions()

  • cfunctions()

  • islocal()

  • isglobal()

  • isfunction()

  • iscfunction()

  • packages()

  • ispackage()

  • classes()

  • isclass()

  • packageclasses()

  • ispackageclass()

  • classname()

  • parentclassname()

  • objectid()

  • isobject()

  • attributes()

  • methods()

  • isattribute()

  • isprivateattribute()

  • ismethod()

  • isprivatemethod()

  • addattribute()

  • addmethod()

  • getattribute()

  • setattribute()

  • mergemethods()

  • packagename()

  • importpackage()

  • nothing()

  • optionalfunc()

locals() Function

We can get a list of variables names in the current scope using the locals() function.

Syntax:

locals() --> a list contains the variables names in the current scope

Example:

test("hello")

func test cMsg

        see cMsg + nl

        x = 10
        y = 20
        z = 30

        see locals()

Output:

hello
cmsg
x
y
z

globals() Function

We can get a list of variables names in the global scope using the globals() function.

Syntax:

globals() --> a list contains variables names in the global scope

Example:

x=10 y=20 z=30
test()

func test
        see "message from test()" + nl +
            "Global Variables:" + nl
        see globals()

Output:

message from test()
Global Variables:
x
y
z

functions() Function

We can get a list of functions names written in the Ring language using the functions() function.

Syntax:

functions() --> a list contains functions names

Example:

see functions()

func f1
        see "f1" + nl

func f2
        see "f2" + nl

func f3
        see "f3" + nl

Output:

f1
f2
f3

cfunctions() Function

We can get a list of functions names written in the C language using the cfunctions() function.

Syntax:

cfunctions() --> a list contains functions names

Example:

aList =  cfunctions()
See "Count : " + len(aList) + nl
for x in aList
        see x + "()" + nl
next

Output:

Count : 254
len()
add()
del()
get()
clock()
...

Note

The complete list is removed from the previous output.

islocal() Function

We can check if a variable is defined in the local scope or not using the islocal() function.

Syntax:

islocal(cVariableName) --> returns 1 if the variable is defined in the local scope
                           returns 0 if the variable is not defined in the local scope

Example:

test()

func test
        x=10 y=20
        see islocal("x") + nl +
            islocal("y") + nl +
            islocal("z") + nl

Output:

1
1
0

isglobal() Function

We can check if a variable is defined in the global scope or not using the isglobal() function.

Syntax:

isglobal(cVariableName) --> returns 1 if the variable is defined in the global scope
                            returns 0 if the variable is not defined in the global scope

Example:

x=10 y=20

test()

func test
        see isglobal("x") + nl +
            isglobal("y") + nl +
            isglobal("z") + nl

Output:

1
1
0

isfunction() Function

We can check if a Ring function is defined or not using the isfunction() function.

Syntax:

isfunction(cFunctionName) --> returns 1 if the Ring function is defined
                              returns 0 if the Ring function is not defined

Example:

see isfunction("f1") + nl +
    isfunction("f2") + nl +
    isfunction("f3") + nl

func f1
        see "message from f1()" + nl

func f2
        see "message from f2()" + nl

Output:

1
1
0

iscfunction() Function

We can check if a C function is defined or not using the iscfunction() function.

Syntax:

iscfunction(cFunctionName) --> returns 1 if the C function is defined
                               returns 0 if the C function is not defined

Example:

see iscfunction("len") + nl +
    iscfunction("add") + nl +
    iscfunction("test") + nl

Output:

1
1
0

packages() Function

We can get a list of packages names using the packages() function.

Syntax:

packages() --> a list contains packages names

Example:

See packages()

Package Package1
        Class class1
                Func f1

Package Package2
        Class class1
                Func f1

Package Package3
        Class class1
                Func f1

Package Package4
        Class class1
                Func f1

Output:

package1
package2
package3
package4

ispackage() Function

We can check if a package is defined or not using the ispackage() function.

Syntax:

ispackage(cPackageName) --> returns 1 if the Package is defined
                            returns 0 if the Package is not defined

Example:

See ispackage("package1") + nl +
    ispackage("package4") + nl +
    ispackage("package5") + nl +
    ispackage("package3") + nl

Package Package1
        Class class1
                Func f1

Package Package2
        Class class1
                Func f1

Package Package3
        Class class1
                Func f1

Package Package4
        Class class1
                Func f1

Output:

1
1
0
1

classes() Function

We can get a list of classes names using the classes() function.

Syntax:

classes() --> a list contains classes names

Example:

See classes()

Class class1
        Func f1

Class class2
        Func f1

Class class3
        Func f1

Output:

class1
class2
class3

isclass() Function

We can check if a class is defined or not using the isclass() function.

Syntax:

isclass(cClassName) -->  returns 1 if the Class is defined
                         returns 0 if the Class is not defined

Example:

see isclass("class4") + nl +
    isclass("class3") + nl +
    isclass("class2") + nl

Class class1
        func f1

class class2
        func f1

class class3
        func f1

Output:

0
1
1

packageclasses() Function

We can get a list of classes names inside a package using the packageclasses() function.

Syntax:

packageclasses(cPackageName) --> a list contains classes names inside the package

Example:

see "classes in Package1" + nl
see packageclasses("Package1")
see "classes in Package2" + nl
see packageclasses("Package2")

Package Package1
        Class class1
                Func f1

Package Package2
        Class class1
                Func f1
        Class class2
                Func f1
        Class class3
                func f1

Output:

classes in Package1
class1
classes in Package2
class1
class2
class3

ispackageclass() Function

We can check if a class is defined inside package or not using the ispackageclass() function.

Syntax:

ispackageclass(cPackageName,cClassName) -->  returns 1 if the Class is defined
                                             returns 0 if the Class is not defined

Example:

see ispackageclass("package1","class1") + nl +
    ispackageclass("package1","class2") + nl +
    ispackageclass("package2","class1") + nl +
    ispackageclass("package2","class2") + nl

Package Package1
        Class class1
                Func f1

Package Package2
        Class class1
                Func f1
        Class class2
                Func f1
        Class class3
                func f1

Output:

1
0
1
1

classname() Function

We can know the class name of an object using the classname() function

Syntax:

classname(object) --> Returns the object class name

Example:

o1 = new point
o2 = new rect

see classname(o1) + nl          # print point
see classname(o2) + nl          # print rect

class point
class rect

parentclassname() Function

We can know the parent class name of an object using the parentclassname() function

Syntax:

parentclassname(object) --> Returns the parent class name of the object class

Example:

new Child  { test() }

class Parent
class Child from Parent
        func test
                ? "Parent: " + parentClassName(self)

Output:

Parent: parent

objectid() Function

We can know the object id using the objectid() function

Syntax:

objectid(object) --> Returns the object id

Example:

o1 = new point
see objectid(o1) + nl
test(o1)

func test v
        see objectid(v) + nl

Class point x y z

Output:

021B5808
021B5808

isobject() Function

We can check the variable to know if it’s an object or not using the isobject() function

Syntax:

isobject(variable) --> Returns True if it's an object, False if it's not

attributes() Function

We can get the object attributes using the attributes() function

Syntax:

attributes(object) --> Returns a list contains the object attributes

Example:

o1 = new point
aList = attributes(o1)          # we can use see attributes(o1)
for t in aList see t next       # print xyz
Class Point x y z

methods() Function

We can get the object methods using the methods() function

Syntax:

methods(object) --> Returns a list contains the object methods

Example:

o1 = new test
aList = methods(o1)

for x in aList
        cCode = "o1."+x+"()"
        eval(cCode)
next

Class Test
        func f1
                see "hello from f1" + nl
        func f2
                see "hello from f2" + nl
        func f3
                see "hello from f3" + nl
        func f4
                see "hello from f4" + nl

Output:

hello from f1
hello from f2
hello from f3
hello from f4

isattribute() Function

We can test if the object contains an attribute or not using the isattribute() function

Syntax:

isattribute(object,cAttributeName) --> Returns True if the object contains the attribute

Example:

o1 = new point

see isattribute(o1,"x") + nl    # print 1
see isattribute(o1,"t") + nl    # print 0
see isattribute(o1,"y") + nl    # print 1
see isattribute(o1,"z") + nl    # print 1

class point x y z

isprivateattribute() Function

We can test if the object contains a private attribute or not using the isprivateattribute() function

Syntax:

isprivateattribute(object,cAttributeName) --> Returns True if the object
                                              contains the private attribute

Example:

o1 = new person

see isprivateattribute(o1,"name") + nl +
    isprivateattribute(o1,"address") + nl +
    isprivateattribute(o1,"phone") + nl +
    isprivateattribute(o1,"job") + nl +
    isprivateattribute(o1,"salary")

Class Person
        name address phone
        private
                job salary

Output:

0
0
0
1
1

ismethod() Function

We can test if the object class contains a method or not using the ismethod() function

Syntax:

ismethod(object,cMethodName) --> Returns True if the object class contains the method

Example:

o1 = new point

see ismethod(o1,"print") + nl           # print 1

mylist = []
mylist + new point

see ismethod(mylist[1],"print") + nl    # print 1

class point x y z
        func print
                see x + nl + y + nl + z + nl

isprivatemethod() Function

We can test if the object class contains a private method or not using the isprivatemethod() function

Syntax:

isprivatemethod(object,cMethodName) --> Returns True if the object class contains
                                        the private method

Example:

o1 = new Test

see isprivatemethod(o1,"f1") + nl +
    isprivatemethod(o1,"f2")

Class Test
        func  f1
                see "message from f1()" + nl
        private
                func f2
                        see "message from f2()" + nl

Output:

0
1

addattribute() Function

We can add an attribute (or a group of attributes) to the object state (not the class) using the addattribute() function

Syntax:

AddAttribute(object,cAttributeName|aAttributesList)

Example(1):

see new point {x=10 y=20 z=30}
Class Point
        AddAttribute(self,["x","y","z"])

Example(2):

o1 = new point
addattribute(o1,"x")
addattribute(o1,"y")
addattribute(o1,"z")
see o1 {x=10 y=20 z=30}
class point

Output:

x: 10.000000
y: 20.000000
z: 30.000000

addmethod() Function

We can add a method to the object class using the addmethod() function This method can be used with any object from the same class.

Syntax:

AddMethod(Object,cNewMethodName,cMethodName|AnonymousFunction)

Example:

o1 = new point { x=10 y=20 z=30 }

addmethod(o1,"print", func { see x + nl + y + nl + z + nl } )

o1.print()

Class point
        x y z

Output:

10
20
30

Instead of using anonymous function to add new method to the class, we can use the function name

Example:

o1 = new point { x=10 y=20 z=30 }

myfunc = func { see x + nl + y + nl + z + nl }

addmethod(o1,"print", myfunc )
addmethod(o1,"display", myfunc )
addmethod(o1,"show", myfunc )

o1.print()
o1.display()
o1.show()

Class point
        x y z

Output:

10
20
30
10
20
30
10
20
30

Since we add the method to the class, any object from that class can use this method

Example:

o1 = new point { x=10 y=20 z=30 }
o2 = new point { x=100 y=200 z=300 }
o3 = new point { x=50 y=150 z=250 }

addmethod(o1,"print", func { see x + nl + y + nl + z + nl } )

o1.print()
o2.print()
o3.print()

Class point
        x y z

Output:

10
20
30
100
200
300
50
150
250

getattribute() function

We can get the object attribute value using the getattribute() function

Syntax:

GetAttribute(oObject,cAttributeName) ---> Attribute Value

Example:

o1 = new point

see getattribute(o1,"name") + nl +
    getattribute(o1,"x") + nl +
    getattribute(o1,"y") + nl +
    getattribute(o1,"z") + nl

Class Point
        x=10 y=20 z=30
        name = "3D-Point"

Output:

3D-Point
10
20
30

Example:

We can Find a Class List Member using GetAttribute() using a function findclass() The Find uses the member name, rather than the column number

myList =
          [new Company {position=3 name="Mahmoud" symbol="MHD"},
           new Company {position=2 name="Bert" symbol="BRT"},
           new Company {position=1 name="Ring" symbol="RNG"}
          ]

see myList
see nl +"=====================" + nl + nl

for i = 1 to len(myList)
     see  "Pos: "+ i +" | "+ myList[i].position +" | "+ myList[i].name +
          " | "+  myList[i].symbol    +" | "+ nl
next


See findclass(myList, "MHD", "symbol") +nl   ### Specify Member class name

###---------------------------------------

func findclass classList, cValue, classMember

       See nl + "FindClass: "  +" "+ cValue + nl + nl

       for i = 1 to len(classList)
            result = getattribute( classList[i], classMember )

           See "Result-Attr: " + i +" "+  result +nl
           if result = cValue
               j = i
            ok
       next
return j

###--------------------------------------

class company position name symbol

Output:

Pos: 1 | 3 | Mahmoud | MHD |
Pos: 2 | 2 | Bert | BRT |
Pos: 3 | 1 | Ring | RNG |

FindClass:  MHD

Result-Attr: 1 MHD
Result-Attr: 2 BRT
Result-Attr: 3 RNG

1

setattribute() function

We can set the object attribute value using the setattribute() function

Syntax:

SetAttribute(oObject,cAttributeName,Value)

Example:

o1 = new person
setattribute(o1,"cName","Mahmoud")
setattribute(o1,"nSalary",1000000)
setattribute(o1,"aColors",["white","blue","yellow"])

see o1
see o1.aColors

Class Person
        cName
        nSalary
        aColors

Output:

cname: Mahmoud
nsalary: 1000000.000000
acolors: List...
white
blue
yellow

mergemethods() Function

We can share methods between classes without inheritance using the MergeMethods() function

This function merge class methods to another class.

Syntax:

MergeMethods(cClassNameDestination,cClassNameSource)

Example:

mergemethods("count","share")
mergemethods("count2","share")

o1 = new count  { test() }
o1 = new count2 { test() }

Class Share
        func one
                see "one" + nl
        func two
                see "two" + nl
        func three
                see "three" + nl

Class Display
        Func printline
                see copy("*",20) + nl

Class Count from Display
        Func test
                printline()
                one()
                two()
                three()
                printline()

Class Count2 from Display
        Func test
                three()
                two()
                one()
                printline()

Output:

********************
one
two
three
********************
three
two
one
********************

packagename() Function

We can know the package name of the latest successful import command using the packagename() function

Syntax:

packagename() --> Returns the package name of the latest successful import

Example:

load "weblib.ring"
import System.web
see packagename()       # system.web

importpackage() Function

Instead of using the import command we can use the importpackage() function

This function get the package name through a string or variable

This is useful if the package name will be known only during the runtime

Syntax:

importpackage(cPackageName)

Example:

importpackage(:mypackage)
new myclass { myfunction() }

package mypackage
        class myclass
                function myfunction
                        ? "Hello, World!"

Nothing() function

This function does nothing and can accept any number/type of parameters. The output will be Zero.

Some of the Use Cases

  1. Performance measurements, where we can test the performance of calling functions written in C and we can change the number of parameters during tests.

  2. In places of code that you want to write a function name, and it’s not defined yet.

  3. To disable some feature/code by just changing the function name to nothing without changing the parameters or commenting the code.

  4. In small programs, where you want to write a function that you can override from a Test program.

OptionalFunc() function

Using this function we can define functions similar to Nothing() but with a different name.

Syntax:

OptionalFunc(cFunctionName)

Example:

File: Question.ring

optionalFunc(:reply)

? "I love Programming, What about you?"
reply()
? "Ok, Thanks!"

Output:

I love Programming, What about you?
Ok, Thanks!

File: Answer.ring

load "Question.ring"

func reply
        ? "Me too!"

Output:

I love Programming, What about you?
Me too!
Ok, Thanks!