Variable name from dictionary key

I am setting up a mechanism in my film scanner software that allows you to save a config file for different types of film to be scanned. Things like default motor torque settings, camera and lens stage positions, etc.

I’m saving them to a text file, probably just a flat key/value pair setup. I first put all the variables I want to save into a dictionary, with the key having the same name as the corresponding Xojo variable, and the value to whatever that value is currently set to. For example:

var configValues as new dictionary
configValues.Value("ConfigName") = tfConfigName.Text

//Camera and lens positions
configValues.Value("imCamStageTarget") = imCamStagePos
configValues.Value("imLensStageTarget") = imLensStagePos

//Transport settings for this gauge
configValues.Value("trCapstanAcceleration") = trCapstanAcceleration
configValues.Value("trCapstanVelocity") = trCapstanVelocity
configValues.Value("trFeedSpeed") = trFeedSpeed
configValues.Value("trFeedTorque") = trFeedTorque
configValues.Value("trTakeupSpeed") = trTakeupSpeed
configValues.Value("trTakeupTorque") = trTakeupTorque

Upon loading a config file, it will read in the text file and write out the default values to the Xojo variables.

The keys are the same names as my variables in the application. When loading a config file, I will put all of the key/value pairs seen above in a new dictionary. Then I’ll walk through that dictionary to populate the variables one at a time.

And here’s where my question comes in:

How do I use the key name to reference a variable? That is, when I’m walking the dictionary and I’m at trCapstanAcceleration, is there a way to translate that key name into the name of the variable? I don’t want to have to set up a complicated switch/case for all the pairs in the dictionary, because there could be several dozen. Ideally I tell it, “set the variable that has the same name as key to value” for each of the key/value pairs.

This will simplify the code a lot, and it means I can add items to the config file without having to add any code for that new pair when parsing the config file.

That would simplify things a lot. There is a similar discussion here: Xojo have a Syntax where Color.Red and Color["Red"] refer to the same thing?

The only way to do this is to set up a class with the properties you need, then use Introspection to match a key to the property name and set its value.

2 Likes

Hmm. That could work, though it still means for each new item we want to add, we have to do it in two places - the dictionary with the key/value pairs from the config file, as well as the class properties, right? In that case, may as well just do the switch/case

Just do the switch/case.

I’m not sure why you’d still need the Dictionary. One function would read the config file into the class, raising an exception (or something) if there is an unrecognized key, the other would write from the class to the config file. In that scenario, whenever you need a new key, you just add it to the class with a default.

If you really do need a Dictionary, the values could be PropertyType from the class so it could read and write directly to your class instance. You’d do either through a function that would take care of the details.

Well it’s six of one half dozen of the other here, when it’s a choice between doing it as a class or a dictionary/switch, I think.

The reason I’m asking about this is because of future flexibility. To add an item to the config file, I’d only need to add it to one place (the the code that populates the dictionary). Upon reading that config file in, a for…next loop would then go through the dictionary and populate the properties in my app, using the dictionary’s key, which would have the same name as the property. It’d just be nice to be able to do that. It’s not a big deal to do it with a switch/case, but it would mean less work. I wouldn’t have to add a case for every property - basically i have to put code in two places, not one, doing it this way.

In my case, anything I’d be adding would involve a pre-existing property in the app anyway, so it’s mainly about having less code, and being able to add items to the config in one spot.

I’ve done this both ways (using Introspection, vs. using a long Select..Case ).

An advantage of Select..Case statement is that you can be very explicit at handling unusual data…

Example:

SetProperty(key as string, v as variant)
select case key
[...]
  case "dateOfBirth"
      // handle an old database which uses uses Jan 1, 0999 for "missing value"
      if v is "09990101" then v = nil 
      me.dateOfBirth = v
[...]
2 Likes

Perhaps I am misunderstanding the issue, but I THINK you are trying to minimize working with a variable name twice. Obviously you are going to have to have the variable name declared somewhere in the code in order to use it or you wouldn’t be adding it and you now want to just add it to the config file and make the two auto-magically link. I can see the merits of this.

Why not use a method that gets passed the variable name and then opens the config file, reads each line looking for it, and then returns the value? That way you can do something like:

Var ScanSpeed As Single
ScanSpeed = ReadConfig(“ScanSpeed”)

This does mean that a large config file may be opened many times, but I use this technique with smaller config files all the time. It greatly simplified reusing code and I finally used it so much that I created a class that does it with just setting up the path to the config file and calling for each variable. I have one optional parameter that tells the method the value to be read is encrypted and it returns the decrypted value.

If you have hundreds of config file variables this is still two lines versus one, but I think it beats Select-Case at the expense of slightly longer file read times.

1 Like

Why not skip the dictionary entirely and set the variables directly when you read the config?

I don’t think I articulated my idea well enough so I created this project to illustrate the idea.

(I would have posted this sooner but I lost Internet for the entire day.)

The MyConfig class defines arbitrary properties like StringProp1 or DoubleProp2. The class can read its values from a given file like var config as MyConfig = MyConfig.FromFile( file ) or write itself back like config.ToFile( file ).

You can also access the properties through the Value method to get or set values, like config.Value( "StringProp1" ) = "some string" or s = config.Value( "StringProp1" ).

New properties need only be added to the class, optionally with a default, and will be immediate accessible in code. There is no need to maintain a separate Dictionary or any Select Case statements.

I hope this helps.

Config PoC.xojo_binary_project.zip (7.7 KB)

2 Likes

Whether it uses a dictionary to store those key/value pairs is neither here nor there - that’s just an easy container to use. What I would like to do is skip the Select Case structure because it’s bulky.

Maybe it wasn’t clear the way I originally wrote it. Here’s what I’m doing. My app has (among many others) the following properties:

feedTorque
feedAcceleration
takeupTorque
takeupAcceleration
capstanSpeed
capstanAcceleration
cameraPosition
lensPosition
exposureTime
cameraBitDepthMode
ledR1
ledR2
ledG
ledB
ledIR

These properties already exist in a module and are referenced throughout the app.

When I create the config file, I use a dictionary to gather up all the values that I want to write to the file. Then I output the key/value pairs in that dictionary to the text file. The dictionary is just a convenient way to contain them all in one place. I don’t need to use one, I just like the structure of it, and it works. It could just as easily be done in some other way.

Now on import of the config file, I am sucking the config file text into a dictionary, and then I loop through that to write out the properties. Again, doesn’t need to be a dictionary per se, it’s just what I’m doing. I could just as easily do it while parsing the text in the config file.

However it’s structured, I need to write a select case statement that addresses each key/value pair in the file, and update the corresponding properties in the app. So:

case feedTorque
 feedTorque = value
case feedAcceleration
 feedAcceleration = value
case takeupTorque
 takeupTorque = value
case takeupAcceleration
 takeupAcceleration = value
case capstanSpeed
 capstanSpeed = value
case capstanAcceleration
 capstanAcceleration = value
case cameraPosition
 cameraPosition = value
case lensPosition
 lensPosition = value
case exposureTime
 exposureTime = value
case cameraBitDepthMode
 cameraBitDepthMode = value
case ledR1
 ledR1 = value
case ledR2
 ledR2 = value
case ledG
 ledG = value
case ledB
 ledB = value
case ledIR
 ledIR = value

Because the config file’s keys have the same names as the app’s properties, I’d like to be able to just iterate through that list and say "set the property called capstanSpeed (which I’m not hardcoding, I’m picking up capstanSpeed from the name of the key) to the value associated with that key. Something like:

For Each key As Variant In configFile.Keys
 <key> = configFile.Value
Next

where <key> is whatever notation would be used to say that the name of the “key” in the loop is also the name of the property I want to update.

This would mean one line of code inside a loop rather than, in this case, 30 lines of code. Even if I changed the name of a property or added a new one, for example, the only code I would need to alter is the line that adds that property to the config file. Next time the file is read in, that new or edited property will get updated with no additional coding.

I understand the limitations here - you wouldn’t be able to check validity of the data, as pointed out above. But this is a closed loop system (writing and reading the config files) so it’s not really a concern in my case.

Thanks. I’ll take a look at this and see if it works for my use case!

Another approach would be to make the properties computed properties. They would then interact with the dictionary to get or set the values. When you add a new property, it just needs to use the new key value to access the dictionary. Everthing is encapsulated in one place. And then the dictionary is ready when it comes time to write it out.

1 Like

they are all computed properties already.

The problem with adding logic in there that interacts with the config file dictionary is that these properties can be set and modified in other parts of the app, and I don’t necessarily want to modify the dictionary every time the value of these properties change.

What I’m doing with Select Case works fine, I just think it would be a nice way to clean up a setup like this. I’ve done similar stuff in PHP using variable variables, and it really does make stuff like this much cleaner. there are obvious downsides, but when you need it it’s very handy.

This is really the defining feature of strictly typed checked languages (like Xojo) and loosely typed languages (PHP, JavaScript, et al). There are some amazingly convenient things you can do in PHP that you cannot do in Xojo, it’s true – but that flexibility means you don’t get the advantages of strict type checking.

Swift is one of a new breed of languages that attempt to bridge this divide by mixing in a little of the syntactic flexibility of PHP, etc. with the type checking of Xojo, etc. They’ve struck a very interesting balance between the two approaches.