Author |
Topic: Variable names from strings (Read 548 times) |
|
Matt
Developer
member is offline


Gender: 
Posts: 210
|
 |
Variable names from strings
« Thread started on: Sep 21st, 2010, 7:32pm » |
|
Hi,
Is there a way of using the result from an input to a string to gain access to another - say in a structure.
I'll try to explain that a little better with an example.
Code:DIM objpos{x,y,z}
objpos.x = 1
objpos.y = 2
objpos.z = 3
...
required_output_from$="y"
...
result%=objpos.[required_output_from$]
REM square brackets to emphasize string
The reason for this would be to be able to gather information from a DB which might include a sub heading such as:
Age="32"
Code:...
INPUT#fn%,line$
REM split line into header$ and age$
...
data.[header$]=age$
...
If this could be done, it would solve a few of my problems.
Matt
|
|
Logged
|
|
|
|
JonR
New Member
member is offline


Posts: 24
|
 |
Re: Variable names from strings
« Reply #1 on: Sep 21st, 2010, 8:38pm » |
|
You could use the EVAL function which takes a string containng a variabler name or an expression, evaluates it and returns the answer. I've taken the liberty of changing the variable result% into the same type as the items inside the objpos structure.
Code: result = EVAL("objpos."+required_output_from$)
However this method is not recommended as it has complications. For instance you need to check that required_output_from$ contains a sensible value to avoid a no such variable error and allow you to deal with unexpected input. You also need to use a REM !Keep compiler directive to ensure that the variable names relating to the structure are kept intact when the program is crunched if you want to use the abbreviate names option. This gives you the rather following unweildy and hard to main code:
Code: REM!Keep objpos,x,y,z
...
IF required_output_from$ = "x" OR required_output_from$ = "y" OR required_output_from$ = "z" THEN
result = EVAL("objpos."+required_output_from$)
ELSE
REM handle unexpected error
ENDIF
There's more in the Wiki article preventing structure member names being crunched. If you extend your structure to contain more members the code would become difficult to maintain very quickly.
A solution with none of the above complications is to check the value of required_output_from$ and return the appropriate structure member. You can use a CASE structure as follows:
Code: CASE required_output_from$ OF
WHEN "x"
result = objpos.x
WHEN "y"
result = objpos.y
WHEN "z"
result = objpos.z
OTHERWISE
REM handle unexpected input
ENDCASE
This is a lot easier to maintain. You could even use this to create a pair of routines to get and set the fields:
Code: DEF FN_getResult(objpos{}, field$)
LOCAL result
CASE field$ OF
WHEN "x"
result = objpos.x
WHEN "y"
result = objpos.y
WHEN "z"
result = objpos.z
OTHERWISE
REM handle unexpected input
ENDCASE
= result
DEF PROC_setResult(objpos{}, field$, number)
CASE field$ OF
WHEN "x"
objpos.x = number
WHEN "y"
objpos.y = number
WHEN "z"
objpos.z = number
OTHERWISE
REM handle unexpected input
ENDCASE
ENDPROC
I tend to deal with structures as opaque objects that I create and interact with indrectly by creating a set of routines that I pass the structure to that manipulate it in various ways instead of accessing the memebrs of the structure directly. I find that taking an object oriented approach allows me to create cleaner self contained code. The above might be extended as follows:
Code: DIM OBJPOS{x,y,x}
REM...
DEF PROC_create(objpos{})
DIM objpos{} = OBJPOS{}
ENDPROC
DEF FN_getX(objpos{})
= objpos.x
DEF PROC_setX(objpos{}, number)
objpos.x = number{}
ENDPROC
DEF FN_getY(objpos{})
= objpos.y
DEF PROC_setY(objpos{}, number)
objpos.x = number{}
ENDPROC
DEF FN_getZ(objpos{})
= objpos.z
DEF PROC_setZ(objpos{}, number)
objpos.z = number{}
ENDPROC
DEF FN_getResult(objpos{}, field$)
LOCAL result
CASE field$ OF
WHEN "x"
result = FN_getX(objpos{})
WHEN "y"
result = FN_getY(objpos{})
WHEN "z"
result = FN_getZ(objpos{})
OTHERWISE
REM handle unexpected input
ENDCASE
= result
DEF PROC_setResult(objpos{}, field$, number)
CASE field$ OF
WHEN "x"
PROC_setX(objpos{})
WHEN "y"
PROC_setY(objpos{})
WHEN "z"
PROC_setZ(objpos{})
OTHERWISE
REM handle unexpected input
ENDCASE
|
« Last Edit: Sep 21st, 2010, 8:56pm by JonR » |
Logged
|
|
|
|
admin
Administrator
member is offline


Posts: 1145
|
 |
Re: Variable names from strings
« Reply #2 on: Sep 21st, 2010, 9:26pm » |
|
on Sep 21st, 2010, 8:38pm, JonR wrote:However this method is not recommended as it has complications. For instance you need to check that required_output_from$ contains a sensible value to avoid a no such variable error and allow you to deal with unexpected input. |
|
Although not generally to be recommended, this is one occasion when allowing the error to occur, and trapping it, might be the most straightforward solution:
Code: DEF FNresult(rof$)
ON ERROR LOCAL = -1
= EVAL("objpos."+rof$) This will return the value of the member whose name is passed to the function (e.g. "x" or "y") or -1 if an error occurs, such as the supplied name not being one of the structure's members.
Nevertheless, I agree that it's probably better to avoid using EVAL this way.
Richard.
|
|
Logged
|
|
|
|
Matt
Developer
member is offline


Gender: 
Posts: 210
|
 |
Re: Variable names from strings
« Reply #3 on: Sep 22nd, 2010, 05:50am » |
|
Thanks Guys,
I'll have to investigate the EVAL for this further as the structure may contain hundreds of members. Producing a CASE for all of them would be very time consuming and possibly erroneous in itself.
Matt
|
|
Logged
|
|
|
|
JonR
New Member
member is offline


Posts: 24
|
 |
Re: Variable names from strings
« Reply #4 on: Sep 22nd, 2010, 07:18am » |
|
The CASE is an easily automatable task ideal for doing programattically. You already have a list of all the names of the structure members so it should be simple to write a code generator to write the CASE for you:
Code: eol$=CHR$13+CHR$10
DIM array$(...)
REM initialise contents with list of items
text$="CASE required_output_from$ OF"+eol$
FOR i%=0 TO DIM(array$(),1)
text$+="WHEN """+array$(i%)+""""+eol$
text$+="result = objpos."+array$(i%)+eol$
NEXT i%
text$+="OTHERWISE"+eol$
text$+="REM handle unexpected input"+eol$
text$+="ENDCASE"
REM set clipboard text
SYS "GlobalAlloc", &2000, LEN(text$)+1 TO hdata%
SYS "GlobalLock", hdata% TO tmp%
$$tmp% = text$
SYS "GlobalUnlock", hdata%
SYS "OpenClipboard", @hwnd%
SYS "EmptyClipboard"
SYS "SetClipboardData", 1, hdata%
SYS "CloseClipboard"
|
« Last Edit: Sep 22nd, 2010, 07:20am by JonR » |
Logged
|
|
|
|
|