Why even use the paradigm of a programming language as the description language if not to employ the features of a programming language that are different in some way from a simple pile of xml?

If you want a variable to actually function as a variable rather than merely a named constant, the only ways you can do it are things like huge ternary else lists that try to pre-handle all eventual possibilities at assign-time, and god help you if the values are expressions rather than simple alternative values,
or passing it as a parameter to a module (function basically) that has to exist for no other reason than so that it can accept a parameter so that it can act like a variable that actually varies.

"scene description" happens to be exactly a great example of a problem. Preview mode, render mode, and importing the file into freecad are 3 distinct contexts that each want 99% the same code with only a few differences. One of those I can't even do. When I want to import a model into freecad, I have to manually comment out $fn $fa $fs and save the file in that condition, just so that freecad will interpret arcs as arcs instead of facets.

Digression there, anyway, for instance, I can't have a set of values that all change based on one other value, because I can't assign those values from within braces, so I can't say if(condition A) {set 50 values the A way...}
I have to have 50 individual repeated condtional assignments, each with the same conditions and the same following string of ternary else other conditions and values

feat1 = opt == "optA" ? valA : opt == "optB" ? valB : opt == "optC" ? valC : ... valF;

feat2 = all those same conditions again...

...

feat50 = all those same conditions...

You might solve that by putting all that stuff into seperate files and having one condition that chooses one file to import, and that file has all simple assignments for a single case, but without having tried it I garantee it only creates some other problem like if the values are actually expressions that need to refer to other values in the main file...

Or in other cases, you have to break up a reasonable module into multiple modules, just so you can have one module with the common/shared features and a few others with the variable features, and a top level wrapper module that just calls the common one and decides which of the variable ones to call, and passes them all any values they need to share which were not in the global scope.

Sometimes this is not too unnatural, but sometimes it's completely ridiculous and wrong, but you have to do it only because openscad provides no better option.

And that still doesn't really show the problem. At least for my models, they are really more like model generators that I want to e highly configurable, and that really needs the ability to conditionally set a value and then overwrite it later, in order for the settings to be most useful for the user.

So for instance, the model has 30 values for various dimensions. Say there a 5 different versions of the model with 5 different sets of the 30 values. So I have either all those ternary lists or some seperate config files like above, or something even worse like 5 different top level wrapper modules that all they do is define a bunch of params to hand to a top level child, that the has to pass everything to every other module in the file...

Anyway, say you have that all done one way or another, you have your variable set of variables.

It's still not done because in the real world the user still needs to modify some of the values even after having chosen one of the main options. They wanted say th battery type B option, which defines a bunch of values based on that, but with 2 of those values modified from that starting point. Too bad. You can't set a default and then overwrite it. You can only find where the value is set and monkey hack that, or create a whole new top level option, copy the entire "battery type B" set to a new set and change your one or two things and call it the "battery type Bx" option...

I end up having to do a lot of putting as many of the possible user knobs as I can think of at the top with long descriptive names, and having some of them act as bounds on other values,
so not just bottom_thickness but also maybe default_bottom_thickness and max_bottom_thickness and min_bottom_thickness etc, and then down in the code where the user isn't meant to go I'll have some expression that evaluates those and everything else to arrive at some actual value botzs or something that gets used in the rest of the file.

It has to be like that because there isn't usually a definitive heirarchy of this value always modifies that value but not the other way around.

Say there are dimA and dimB and d8mC, and they are all interrelated where say they must all sum to dimD, and all 4 can be set by the user. I don't know what the real values will be in the rest of the code until I know which if any of those values the user customized. So all of them have to start out as just provisional values. So I need seperately, a default dimA, a possibly user modified dimA, and finally a derived dimA that is actually used in the rest of the file. The default and user-set can't be the same either. Ypu can't just put dimA B C D at the top to be edited. If the user changes dimB, then maybe dimA needs to automatically adjust. if the user changes dimA, then maybe dimB or C needs to automatically adjust, and I may have perfectly good rules for that so that there is no reason not to make them automatic rather than just require the user to supply all good values.

So I have to define some default values that can't be changed, provide a whole duplicate set of possibly user defined overrides, which can't be changed, and derive from those yet another set of values that actually gets used in the rest of the file.

Maybe that isn't even the worst example, and maybe I'm not doing a good job communicating, but the stateless functional nature, makes the tool not that useful for something that is practically it's signature advertised feature, being a parameteic model generator rather than a static model describer.