Dear Khang
Your observation that {{ a["key"] }} doesn't work but {{ a.key }} does is interesting. I don't fully understand this myself, but I can cast a little light on it.
In the first example you quote, the variable 'a' is defined within Twig itself. But when you define 'a' via a template parameter it is actually a JSON object, that is evaluated (using PHP's json_decode) when the question attempt begins to yield a PHP value. That value is then passed as a parameter to the Twig render method of the template. In my call to json_decode I use my default settings, which are to yield a PHP object. It seems that Twig respects the object nature of the parameter and rejects the first of your two usages. However, if I change the json_decode call to instead yield a PHP associative array, it seems that both your two usages work.
So it might well be that a change to the call to Twig render would allow your desired associative usage. However, I'm sorry, but I'm not prepared to make that change, as I don't know what other consequences there might be. You're the first person who has ever drawn my attention to this and I feel the risks are just too great. Happily, though, it seems you've found a solution yourself, via your clever json_encode filter. Alternatively - and this might be easier - I think you can use Twig's attribute function to access a particular attribute of an object, e.g.
attribute(a, "key")
seems to work (though I've never used this before myself).
You way of using the gapfiller UI for use is interesting. As you say, it does seem on the face of it much simpler than using a Python template to reconstruct the code then compile and run it. All the same, that's what we do. We have made this into a question type (or two actually, one for Python and one for C) so it only has to be done once. Thereafter, in all gap filler questions you simply fill in the globalextra with the code into which gaps are inserted. Once saved, the question answer field displays the code with gaps in it, and you can fill out the sample answer by just filling in the gaps, like the students do. The other big advantage of this approach is that you can now add other constraints, such as disallowing certain constructs, requiring others and so on, via template parameters. You can see an example of our python3_html_gapfiller on github here. You'll also find an exciting new style of gapfiller question implemented recently by Matthew Toohey, which implements on-line gapfiller questions within the Ace editor, which looks much nicer than the HTML gap filler. Unfortunately you won't be able to use this yet as it uses a new UI plugin and also requires a tweak to the PHP code, neither of which are yet available in the master branch.
You'll doubtless be horrified at the complexity of those question types but remember they only have to be written once. Compiling and running C or C++ from within such a template is a relatively trivial addition, and indeed we always run such languages from within a Python template nowadays in order to implement style constraints or perform transformation to the student's code or control compiler options, etc.