Function calls in keymap definition

The longer I think about it, the more I see that this would actually be feasible, given the fact that the firmware is a monolith that is compiled as a whole.
It’s a pitty that using such an approach would mean to rewrite most of Kaleidoscope. :persevere:

A key would be an object. This would be both, extremely efficient and powerful.

FWIW, turing completeness is not a prerequisite here.

It isn’t. Libraries are separate units of compilation, and so is the sketch. They do get linked together at the end, but they are compiled separately.

Ok, let me rephrase. The firmware is a monolith were all parts are compiled at the same time and could thus easily be part of a single compilation unit.

The important point is that all compilation units can share information provided e.g. in a central header. That way type information is known across the boundaries of compilation units.

This is fundamentally different from the way how compiler language software is usually build. No run time linking and theoretically no need for signature compatible function APIs. Parts of the software can be combined as long as function names match an accept the same arguments. Here it is important to mention that accepting the same arguments and having the same signature is from a C++ point of view a difference. The two functions

void f(int);

and

void f(double);

both accept an int argument but don’t have the same signature.

An example are e.g. the hardware modules/classes in Kaleidoscope. It would be sufficient for them to accept the same arguments to be compatible.

This is a bit like duck typing.

1 Like

For the record, I do not want to store function pointers in the keymap, nor did I ever. That was a misunderstanding of my original question.

I’m starting to consider removing all the TMP stuff in favor of a sketch builder written in a more comprehensible language. This would have the added advantage of more flexibility — for example, different plugin ordering would be possible in two different hook functions (one plugin could be first in one hook, but last in another).

You should have, because it would have been a good idea. A function pointer to a stateless lambda-function is a compile time constant and would have given you exactly what you want, with no templates involved - if it wasn’t for the 16bit restriction that algernon mentioned.

That will make it even more confusing for users. Better to find a way that does work with an arbitrary order.

But when call orders really matter, a simple wrapper class that implements all hook methods could give you the same already. It would forward the hook calls to plugin instances, with an individual order for each hook method. No extra PROGMEM consumption involved.

If you are interested I can add an example here.

Speak for yourself, and try to refrain from such insulting comments. No, it would not have been a good idea, because it would have made the code make less sense to me. If you want to make sketches less accessible to people who are not already C++ experts, by all means push for use of function pointers, but stop trying to tell me what I want.

Again, speak for yourself. And, as you’re so fond of pointing out, it’s not even theoretically possible to make it so that plugin order doesn’t matter.

You’re also assuming that the user would be choosing plugin order, rather than simply selecting which plugins to use, configuring them, and letting the sketch builder determine order of plugin hook functions.

The function pointer would of course be hidden behind a

QK(A, LShift)

as requested. It would make the sketch more accessible. That’s what you were asking for, in the first place.

Under the hood, QK(...) could read

#define QK(PRI, ALT) \
    &[](/*function parameters*/){ \
     /* function body that does whatever with PRI and ALT*/ \
   }

This is a community forum. The idea to use function pointers was not mine, but I thought the information that and how they could be used in the keymap (as compiletime constant) might be valuable for you and for others in other places. The 16bit restriction aside, for your OP they are (theoretically) the only solution.

@merlin, you are a very valuable member of this community. I like your contributions a lot. You are really moving this project forward. By no means did I intend to insult you and if I did, please accept my apologies.

1 Like

This is all at least partially my fault for taking the thread on a tangent.

That being said, newbie-friendliness, patience, compassion, and respect for different viewpoints or skill levels are critically important to the Kaleidoscope community. Be excellent to each other. If you feel like someone else in the community is being disrespectful or aggressive or otherwise violating the code of conduct, please reach out to me, either by private message here or by email to jesse@keyboard.io. If i’m the one who’s being a problem, please reach out to kaia@keyboard.io.

As to what kinds of metaprogramming we end up with: Whatever we do needs to be easy for novice programmers to use and understand, even if the theoretical underpinnings are complex.
There is definitely a place for tools in friendly scripting languages to generate sketches – kaleidoscope actually started that way.

There may also be a place for deep and scary C++ magic to give us the same features without an external tool. But I’m pretty conservative about how we’re going to do things in the core. I’ve spent a lot of the past few decades of my career dealing with complex codebases with deep, scary magic that, at one point, seemed like a really brilliant idea. (Often times, it was my “brilliant” idea.) Anything we end up with needs to have clean, simple, APIs for end users (including plugin authors) to use. Ideally, they should be well documented and tested. The less like the ‘rest’ of Arduino they are, the more documentation and tests they need. If we have to choose between Kaleidoscope being the most powerful keyboard firmware out there and being approachable by novices, I’m going to choose that it be approachable by novices. (Ideally, it’ll be both.)

(If there’s further discussion on this topic, I’ll pull these bits out into a separate thread.)

4 Likes